diff --git a/.editorconfig b/.editorconfig index 28985f91..a045e3e0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -191,4 +191,8 @@ dotnet_diagnostic.SA1602.severity = none dotnet_diagnostic.SA1202.severity = none [**/Migrations/**/*.cs] -dotnet_analyzer_diagnostic.severity = none \ No newline at end of file +dotnet_analyzer_diagnostic.severity = none + +[*.razor] +dotnet_diagnostic.S927.severity = none +dotnet_diagnostic.S2696.severity = none \ No newline at end of file diff --git a/.gitignore b/.gitignore index f941d0e2..46c6c204 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ # NetEvent specific NetEvent/Client/wwwroot/lib/ +NetEvent/Client/wwwroot/js/ # User-specific files *.rsuser diff --git a/.sonarlint/lan2play_netevent_css_settings.json b/.sonarlint/lan2play_netevent_css_settings.json new file mode 100644 index 00000000..e554bebb --- /dev/null +++ b/.sonarlint/lan2play_netevent_css_settings.json @@ -0,0 +1,122 @@ +{ + "sonarlint.rules": { + "css:S4659": { + "level": "On", + "parameters": { + "ignorePseudoClasses": "local,global,export,import,deep" + }, + "severity": "Major" + }, + "css:S4655": { + "level": "On", + "severity": "Major" + }, + "css:S4670": { + "level": "On", + "parameters": { + "ignoreTypes": "/^(mat|md|fa)-/", + "ignore": "custom-elements" + }, + "severity": "Critical" + }, + "css:S4649": { + "level": "On", + "severity": "Major" + }, + "css:S4662": { + "level": "On", + "parameters": { + "ignoreAtRules": "value,at-root,content,debug,each,else,error,for,function,if,include,mixin,return,warn,while,extend,use,forward,tailwind,apply,layer,/^@.*/" + }, + "severity": "Major" + }, + "css:S4667": { + "level": "On", + "severity": "Major" + }, + "css:S4648": { + "level": "On", + "severity": "Major" + }, + "css:S4647": { + "level": "On", + "severity": "Blocker" + }, + "css:S1116": { + "level": "On", + "severity": "Minor" + }, + "css:S1128": { + "level": "On", + "severity": "Minor" + }, + "css:S4656": { + "level": "On", + "parameters": { + "ignoreFallbacks": "true" + }, + "severity": "Major" + }, + "css:S4666": { + "level": "On", + "severity": "Major" + }, + "css:S4668": { + "level": "On", + "severity": "Blocker" + }, + "css:S4661": { + "level": "On", + "severity": "Major" + }, + "css:S4663": { + "level": "On", + "severity": "Minor" + }, + "css:S4660": { + "level": "On", + "parameters": { + "ignorePseudoElements": "ng-deep,v-deep,deep" + }, + "severity": "Major" + }, + "css:S4654": { + "level": "On", + "parameters": { + "ignoreSelectors": "/^:export.*/, /^:import.*/", + "ignoreTypes": "composes, /^mso-/" + }, + "severity": "Blocker" + }, + "css:S4657": { + "level": "On", + "severity": "Critical" + }, + "css:S4651": { + "level": "On", + "severity": "Critical" + }, + "css:S4650": { + "level": "On", + "severity": "Blocker" + }, + "css:S4653": { + "level": "On", + "severity": "Blocker" + }, + "css:S4652": { + "level": "On", + "severity": "Major" + }, + "css:S4658": { + "level": "On", + "severity": "Major" + }, + "css:S5362": { + "level": "Off" + }, + "css:S4664": { + "level": "Off" + } + } +} \ No newline at end of file diff --git a/.sonarlint/lan2play_netevent_secrets_settings.json b/.sonarlint/lan2play_netevent_secrets_settings.json new file mode 100644 index 00000000..1a0a4ae7 --- /dev/null +++ b/.sonarlint/lan2play_netevent_secrets_settings.json @@ -0,0 +1,32 @@ +{ + "sonarlint.rules": { + "secrets:S6338": { + "level": "On", + "severity": "Blocker" + }, + "secrets:S6337": { + "level": "On", + "severity": "Blocker" + }, + "secrets:S6290": { + "level": "On", + "severity": "Blocker" + }, + "secrets:S6334": { + "level": "On", + "severity": "Blocker" + }, + "secrets:S6336": { + "level": "On", + "severity": "Blocker" + }, + "secrets:S6335": { + "level": "On", + "severity": "Blocker" + }, + "secrets:S6292": { + "level": "On", + "severity": "Blocker" + } + } +} \ No newline at end of file diff --git a/CodeCoverage.runsettings b/CodeCoverage.runsettings index 53ebac6a..2689a749 100644 --- a/CodeCoverage.runsettings +++ b/CodeCoverage.runsettings @@ -1,5 +1,5 @@ - - .*Migrations.* - - + .*Migrations.* + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index de4be40c..7198a244 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,17 +7,18 @@ LABEL stage=builder LABEL org.opencontainers.image.authors="Alexander@volzit.de" #args -ARG NETEVENTNETVER +ARG NETEVENTNETVER=0.0.1 ENV NETEVENTNETVER=$NETEVENTNETVER #install prereqs WORKDIR / RUN apt-get update -qqy && DEBIAN_FRONTEND=noninteractive apt-get install -y \ wget bash apt-transport-https +RUN wget -q -O - https://deb.nodesource.com/setup_current.x | bash - RUN wget https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages-microsoft-prod.deb RUN dpkg -i packages-microsoft-prod.deb RUN rm packages-microsoft-prod.deb -RUN apt-get update -qqy && apt-get install -y dotnet-sdk-7.0 python3 python3-pip wget +RUN apt-get update -qqy && apt-get install -y dotnet-sdk-7.0 python3 python3-pip nodejs RUN pip install lastversion RUN eval apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* @@ -61,13 +62,14 @@ RUN chmod +x /usr/local/bin/start-container RUN chmod +x /usr/local/bin/wait-for.sh #install prereqs -RUN apt-get update -qqy && DEBIAN_FRONTEND=noninteractive apt-get install -y \ - wget apt-transport-https -RUN wget https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages-microsoft-prod.deb -RUN dpkg -i packages-microsoft-prod.deb -RUN rm packages-microsoft-prod.deb -RUN apt-get update -qqy && apt-get install -y aspnetcore-runtime-7.0 netcat curl -RUN eval apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +RUN apt-get update -qqy && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y wget apt-transport-https && \ + wget https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && \ + dpkg -i packages-microsoft-prod.deb && \ + rm packages-microsoft-prod.deb && \ + apt-get update -qqy && \ + apt-get install -y aspnetcore-runtime-7.0 netcat curl && \ + eval apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* #copy NetEvent files WORKDIR /NetEvent diff --git a/NetEvent.sln b/NetEvent.sln index dd63480f..6a348250 100644 --- a/NetEvent.sln +++ b/NetEvent.sln @@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig .gitignore = .gitignore CodeCoverage.runsettings = CodeCoverage.runsettings + NetEvent\Directory.Build.props = NetEvent\Directory.Build.props Makefile = Makefile NetEvent\TestHelper\NetEvent.TestHelper.csproj = NetEvent\TestHelper\NetEvent.TestHelper.csproj README.md = README.md diff --git a/NetEvent/Client.Tests/NetEvent.Client.Tests.csproj b/NetEvent/Client.Tests/NetEvent.Client.Tests.csproj index 4a82bca8..41d9a701 100644 --- a/NetEvent/Client.Tests/NetEvent.Client.Tests.csproj +++ b/NetEvent/Client.Tests/NetEvent.Client.Tests.csproj @@ -11,6 +11,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/NetEvent/Client/Components/Administration/SystemSettingControl.razor b/NetEvent/Client/Components/Administration/SystemSettingControl.razor index a2f243d8..89c11ac9 100644 --- a/NetEvent/Client/Components/Administration/SystemSettingControl.razor +++ b/NetEvent/Client/Components/Administration/SystemSettingControl.razor @@ -18,7 +18,7 @@ { - + } diff --git a/NetEvent/Client/Components/Administration/SystemSettingGroupTab.razor b/NetEvent/Client/Components/Administration/SystemSettingGroupTab.razor new file mode 100644 index 00000000..5fa45796 --- /dev/null +++ b/NetEvent/Client/Components/Administration/SystemSettingGroupTab.razor @@ -0,0 +1,18 @@ + + @if (_Loading) + { +
@Localizer["Administration.Settings.LoadingData"]
+ } + else + { + + @foreach (var systemSetting in SettingsGroup.Settings) + { + + + + } + + } + +
\ No newline at end of file diff --git a/NetEvent/Client/Components/Administration/SystemSettingGroupTab.razor.cs b/NetEvent/Client/Components/Administration/SystemSettingGroupTab.razor.cs new file mode 100644 index 00000000..12416967 --- /dev/null +++ b/NetEvent/Client/Components/Administration/SystemSettingGroupTab.razor.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using NetEvent.Client.Services; +using NetEvent.Shared.Config; +using NetEvent.Shared.Dto; + +namespace NetEvent.Client.Components.Administration +{ + public partial class SystemSettingGroupTab + { + #region Injects + + [Inject] + private IStringLocalizer Localizer { get; set; } = default!; + + [Inject] + private ISystemSettingsDataService SystemSettingsDataService { get; set; } = default!; + + #endregion + + #region Parameters + + [Parameter] + public ISettingsGroup SettingsGroup { get; set; } = default!; + + #endregion + + private IList _Data = new List(); + private bool _Loading = true; + + protected override async Task OnInitializedAsync() + { + var cts = new CancellationTokenSource(); + _Data = await SystemSettingsDataService.GetSystemSettingsAsync(SettingsGroup.SettingGroup, cts.Token); + _Loading = false; + } + + private SystemSettingValueDto? GetValue(string key) + { + return _Data.FirstOrDefault(x => x.Key.Equals(key, StringComparison.Ordinal)) + ?? new SystemSettingValueDto(key, string.Empty); + } + } +} diff --git a/NetEvent/Client/Extensions/CurrencyConverter.cs b/NetEvent/Client/Extensions/CurrencyConverter.cs new file mode 100644 index 00000000..9a0b22dc --- /dev/null +++ b/NetEvent/Client/Extensions/CurrencyConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Globalization; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Client.Extensions +{ + public class CurrencyConverter : MudBlazor.Converter + { + private readonly CurrencyDto _Currency; + + public CurrencyConverter(CurrencyDto currency) + { + SetFunc = ToInputValue; + GetFunc = ToCurrencyValue; + _Currency = currency; + } + + private int ToCurrencyValue(string arg) + { + if (!double.TryParse(arg, CultureInfo.InvariantCulture, out var value)) + { + return 0; + } + + return _Currency.ToCurrencyBaseValue(value); + } + + private string ToInputValue(int arg) + { + return Convert.ToString(_Currency.ToCurrencyValue(arg), Culture); + } + } +} diff --git a/NetEvent/Client/Extensions/TinyMceConfig.cs b/NetEvent/Client/Extensions/TinyMceConfig.cs index 1a6d36ca..e9b308be 100644 --- a/NetEvent/Client/Extensions/TinyMceConfig.cs +++ b/NetEvent/Client/Extensions/TinyMceConfig.cs @@ -10,6 +10,8 @@ public static class TinyMceConfig private const int _HeaderHeight = 64; private const int _EditorHeight = 500; + public const string ScriptSrc = "/lib/tinymce/tinymce.min.js"; + /// /// Provide Editor Config for TinyMce /// More Information: https://www.tiny.cloud/docs/tinymce/6/editor-important-options/ diff --git a/NetEvent/Client/Extensions/UrlHelper.cs b/NetEvent/Client/Extensions/UrlHelper.cs index db408a32..433f73fd 100644 --- a/NetEvent/Client/Extensions/UrlHelper.cs +++ b/NetEvent/Client/Extensions/UrlHelper.cs @@ -21,5 +21,10 @@ public static string GetVenueLink(object id, bool edit) return $"/venue/{id}"; } + + public static string GetTicketTypesLink(object eventId, object id) + { + return $"/administration/event/{eventId}/tickettype/{id}"; + } } } diff --git a/NetEvent/Client/JavaScripts/package-lock.json b/NetEvent/Client/JavaScripts/package-lock.json new file mode 100644 index 00000000..2e3a1de3 --- /dev/null +++ b/NetEvent/Client/JavaScripts/package-lock.json @@ -0,0 +1,3585 @@ +{ + "name": "NetEvent", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "NetEvent", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@adyen/adyen-web": "^5.32.0" + }, + "devDependencies": { + "css-loader": "^6.7.3", + "eslint": "^8.34.0", + "eslint-config-standard": "^17.0.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^15.6.1", + "eslint-plugin-promise": "^6.1.1", + "style-loader": "^3.3.1", + "webpack": "^5.75.0", + "webpack-cli": "^5.0.1" + } + }, + "node_modules/@adyen/adyen-web": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@adyen/adyen-web/-/adyen-web-5.35.0.tgz", + "integrity": "sha512-2WjRTXoNq/laUIymufeyo5CgOHM2+nIdpxzSeIcAU6AH9qvLLpcfRcLkR+VDiFC32wj7PGSrrEDe6sLYSyq0sg==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@babel/runtime-corejs3": "^7.20.1", + "@types/applepayjs": "^3.0.4", + "@types/googlepay": "^0.6.2", + "classnames": "^2.3.1", + "core-js-pure": "^3.25.3", + "preact": "10.11.3" + } + }, + "node_modules/@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz", + "integrity": "sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==", + "dependencies": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz", + "integrity": "sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.35.0.tgz", + "integrity": "sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "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, + "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, + "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, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/applepayjs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/applepayjs/-/applepayjs-3.0.4.tgz", + "integrity": "sha512-RqaVZWy1Kj4e1PoUoOI8uA+4UuuLpicQFxfU9Y/xWJFZFT6mFB4PiiY911iDxFk7pdvaj5HKH7VsWRisRca1Rg==" + }, + "node_modules/@types/eslint": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.1.tgz", + "integrity": "sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/googlepay": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@types/googlepay/-/googlepay-0.6.4.tgz", + "integrity": "sha512-PTt/UCllzl8z5HmhymPpSj6uENZvVKZvCBYdDVmbBVJnLStitxtWrterAOQZkKGlqVdzxNXYeif5hOAMNMS5mw==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", + "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "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, + "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, + "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 + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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 + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001462", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001462.tgz", + "integrity": "sha512-PDd20WuOBPiasZ7KbFnmQRyuLE7cFXW2PVd7dmALzbkUXEP46upAuCDm9eY9vho8fgNMGmbAX92QBZHzcnWIqw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "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 + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/core-js-pure": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.29.0.tgz", + "integrity": "sha512-v94gUjN5UTe1n0yN/opTihJ8QBWD2O8i19RfTZR7foONPWArnjB96QA/wk5ozu1mm6ja3udQCzOzwQXTxi3xOQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.19", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.324", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.324.tgz", + "integrity": "sha512-m+eBs/kh3TXnCuqDF6aHLLRwLK2U471JAbZ1KYigf0TM96fZglxv0/ZFBvyIxnLKsIWUoDiVnHTA2mhYz1fqdA==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz", + "integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^2.0.0", + "@eslint/js": "8.35.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-standard": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", + "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", + "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" + } + ], + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-es": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", + "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", + "dev": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-n": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.6.1.tgz", + "integrity": "sha512-R9xw9OtCRxxaxaszTQmQAlPgM+RdGjaL1akWuY/Fv9fRAi8Wj4CUKc6iYVG8QNRjRuo8/BqVYIpfqberJUEacA==", + "dev": true, + "dependencies": { + "builtins": "^5.0.1", + "eslint-plugin-es": "^4.1.0", + "eslint-utils": "^3.0.0", + "ignore": "^5.1.1", + "is-core-module": "^2.11.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "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, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "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, + "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 + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/preact": { + "version": "10.11.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz", + "integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "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, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.5.tgz", + "integrity": "sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.76.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz", + "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", + "colorette": "^2.0.14", + "commander": "^9.4.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/NetEvent/Client/JavaScripts/package.json b/NetEvent/Client/JavaScripts/package.json new file mode 100644 index 00000000..5d467918 --- /dev/null +++ b/NetEvent/Client/JavaScripts/package.json @@ -0,0 +1,27 @@ +{ + "name": "NetEvent", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "webpack --config webpack.config.js --mode=production", + "build-dev": "webpack --config webpack.config.js --mode=development" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "css-loader": "^6.7.3", + "eslint": "^8.34.0", + "eslint-config-standard": "^17.0.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^15.6.1", + "eslint-plugin-promise": "^6.1.1", + "style-loader": "^3.3.1", + "webpack": "^5.75.0", + "webpack-cli": "^5.0.1" + }, + "dependencies": { + "@adyen/adyen-web": "^5.32.0" + } +} diff --git a/NetEvent/Client/JavaScripts/src/.eslintrc.json b/NetEvent/Client/JavaScripts/src/.eslintrc.json new file mode 100644 index 00000000..ce3a62db --- /dev/null +++ b/NetEvent/Client/JavaScripts/src/.eslintrc.json @@ -0,0 +1,15 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": "standard", + "overrides": [ + ], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": { + } +} diff --git a/NetEvent/Client/JavaScripts/src/checkout.js b/NetEvent/Client/JavaScripts/src/checkout.js new file mode 100644 index 00000000..53e22d0a --- /dev/null +++ b/NetEvent/Client/JavaScripts/src/checkout.js @@ -0,0 +1,82 @@ +import AdyenCheckout from '@adyen/adyen-web' +import '@adyen/adyen-web/dist/adyen.css' + +const configuration = { + // paymentMethodsResponse: paymentMethodsResponse, // The `/paymentMethods` response from the server. + // clientKey: "YOUR_CLIENT_KEY", // Web Drop-in versions before 3.10.1 use originKey instead of clientKey. + locale: 'de-DE', + environment: 'test', + analytics: { + enabled: false // Set to false to not send analytics data to Adyen. + } + // paymentMethodsConfiguration: { + // card: { // Example optional configuration for Cards + // hasHolderName: true, + // holderNameRequired: true, + // enableStoreDetails: true, + // hideCVC: false, // Change this to true to hide the CVC field for stored cards + // name: 'Credit or debit card', + // onSubmit: () => { }, // onSubmit configuration for card payments. Overrides the global configuration. + // } + // } +} + +export async function startPaymentAsync (clientKey, paymentMethods, checkoutTickets) { + configuration.clientKey = clientKey + configuration.paymentMethodsResponse = JSON.parse(paymentMethods) + + configuration.onSubmit = (state, dropin) => { + // Global configuration for onSubmit + // Your function calling your server to make the `/payments` request + checkoutTickets.invokeMethodAsync('MakePayment', state.data) + .then(response => { + const responseData = JSON.parse(response) + if (responseData.action) { + // Drop-in handles the action object from the /payments response + dropin.handleAction(responseData.action) + } else { + // Your function to show the final result to the shopper + // dropin.setStatus(responseData.ResultCode); + checkoutTickets.invokeMethodAsync('ShowResult', responseData.ResultCode, responseData.RefusalReasonCode) + } + }) + .catch(error => { + throw Error(error) + }) + } + + configuration.onAdditionalDetails = (state, dropin) => { + // Your function calling your server to make a `/payments/details` request + checkoutTickets.invokeMethodAsync('MakeDetailsCall', state.data) + .then(response => { + if (response.action) { + // Drop-in handles the action object from the /payments response + dropin.handleAction(response.action) + } else { + // Your function to show the final result to the shopper + // dropin.setStatus(responseData.ResultCode); + // checkoutTickets.invokeMethod('ShowResult', responseData.ResultCode, responseData.RefusalReasonCode) + } + }) + .catch(error => { + throw Error(error) + }) + } + + // Create an instance of AdyenCheckout using the configuration object. + const checkout = await AdyenCheckout(configuration) + // Access the available payment methods for the session. + console.log(clientKey) + console.log(checkout.paymentMethodsResponse) + + // Create an instance of the Component and mount it to the container you created. + checkout + .create('dropin', { + // Starting from version 4.0.0, Drop-in configuration only accepts props related to itself and cannot contain generic configuration like the onSubmit event. + openFirstPaymentMethod: false + }) + .mount('#dropin-container') + + // TODO Handle RedirectResult + // https://docs.adyen.com/online-payments/web-components#handle-redirect-result +}; diff --git a/NetEvent/Client/JavaScripts/src/index.js b/NetEvent/Client/JavaScripts/src/index.js new file mode 100644 index 00000000..0459ee5d --- /dev/null +++ b/NetEvent/Client/JavaScripts/src/index.js @@ -0,0 +1 @@ +// empty file required for webpack \ No newline at end of file diff --git a/NetEvent/Client/JavaScripts/webpack.config.js b/NetEvent/Client/JavaScripts/webpack.config.js new file mode 100644 index 00000000..910f1e0f --- /dev/null +++ b/NetEvent/Client/JavaScripts/webpack.config.js @@ -0,0 +1,18 @@ +module.exports = { + entry: { + checkout: './src/checkout.js', + }, + output: { + filename: '[name].js', + library: 'checkout', + path: __dirname + '/../wwwroot/js', + }, + module: { + rules: [ + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + }, + ], + }, +}; \ No newline at end of file diff --git a/NetEvent/Client/NetEvent.Client.csproj b/NetEvent/Client/NetEvent.Client.csproj index 9a5be8c7..9813c3dd 100644 --- a/NetEvent/Client/NetEvent.Client.csproj +++ b/NetEvent/Client/NetEvent.Client.csproj @@ -23,6 +23,7 @@ + @@ -35,7 +36,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -57,4 +58,10 @@ true + + + + + + diff --git a/NetEvent/Client/Pages/Administration/Events/Event.razor b/NetEvent/Client/Pages/Administration/Events/Event.razor index 901a56f8..02000dbb 100644 --- a/NetEvent/Client/Pages/Administration/Events/Event.razor +++ b/NetEvent/Client/Pages/Administration/Events/Event.razor @@ -1,6 +1,5 @@ @page "/administration/event/{id}" @attribute [Authorize(Policy = "Admin.Events.*")] -@inject Microsoft.Extensions.Localization.IStringLocalizer Localize @using Microsoft.AspNetCore.Authorization @using NetEvent.Client.Components @@ -9,7 +8,6 @@ @using NetEvent.Shared.Config @using NetEvent.Shared.Dto @using NetEvent.Shared.Dto.Event -@using TinyMCE.Blazor @if (_Loading) { @@ -23,137 +21,15 @@ @if (_Event.Id > 0) { - + } - - - - - @Localize["Administration.Events.Event.Settings"] - - - - - @if (_Event.Id > 0) - { - - - - } - - - - - - - - @foreach (var eventFormat in Enum.GetValues()) - { - @Localize["Administration.Events.Event.EventFormat." + @eventFormat.ToString()] - } - - - - - @foreach (var publishState in Enum.GetValues()) - { - @Localize["Administration.Events.Event.PublishState." + @publishState.ToString()] - } - - - - - @foreach (var visibilityState in Enum.GetValues()) - { - @Localize["Administration.Events.Event.VisibilityState." + @visibilityState.ToString()] - } - - - - - - @foreach (var venue in _Venues) - { - @venue.Name - } - - - - - - - - - - - - - - - - - - - - - - - - @(_Event.Id >= 0 ? Localize["Administration.Events.Event.Save"] : Localize["Administration.Events.Event.Create"]) - - - + + @if(_Event.Id > 0) + { + + } } \ No newline at end of file diff --git a/NetEvent/Client/Pages/Administration/Events/Event.razor.cs b/NetEvent/Client/Pages/Administration/Events/Event.razor.cs index 8bb5dc2f..26883d8a 100644 --- a/NetEvent/Client/Pages/Administration/Events/Event.razor.cs +++ b/NetEvent/Client/Pages/Administration/Events/Event.razor.cs @@ -5,11 +5,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Localization; -using MudBlazor; -using NetEvent.Client.Extensions; using NetEvent.Client.Services; using NetEvent.Shared.Dto.Event; -using NetEvent.Shared.Validators; namespace NetEvent.Client.Pages.Administration.Events { @@ -23,15 +20,9 @@ public partial class Event [Inject] private IVenueService VenueService { get; set; } = default!; - [Inject] - private ISnackbar Snackbar { get; set; } = default!; - [Inject] private IStringLocalizer Localizer { get; set; } = default!; - [Inject] - private NavigationManager NavigationManager { get; set; } = default!; - #endregion [Parameter] @@ -40,9 +31,7 @@ public partial class Event private const int _HourOffset = 12; private const int _DayOffset = 2; - private readonly EventModelFluentValidator _EventValidator = new(); private bool _Loading = true; - private MudForm? _Form = default!; private EventDto _Event = default!; private List _Venues = new(); @@ -66,39 +55,5 @@ protected override async Task OnInitializedAsync() _Loading = false; } - - private async Task SaveEvent() - { - if (_Form == null) - { - return; - } - - await _Form.Validate(); - - if (_Form.IsValid) - { - var cts = new CancellationTokenSource(); - ServiceResult result; - if (_Event.Id >= 0) - { - result = await EventService.UpdateEventAsync(_Event, cts.Token); - } - else - { - result = await EventService.CreateEventAsync(_Event, cts.Token); - - if (result.Successful && _Event?.Id != null) - { - NavigationManager.NavigateTo(UrlHelper.GetEventLink(_Event.Id, true)); - } - } - - if (!string.IsNullOrEmpty(result.MessageKey)) - { - Snackbar.Add(Localizer.GetString(result.MessageKey), result.Successful ? Severity.Success : Severity.Error); - } - } - } } } diff --git a/NetEvent/Client/Pages/Administration/Events/EventSettings.razor b/NetEvent/Client/Pages/Administration/Events/EventSettings.razor new file mode 100644 index 00000000..64e66b51 --- /dev/null +++ b/NetEvent/Client/Pages/Administration/Events/EventSettings.razor @@ -0,0 +1,132 @@ +@using NetEvent.Shared.Dto.Event; +@using NetEvent.Shared.Dto; +@using TinyMCE.Blazor; + + + + + + @Localizer["Administration.Events.Event.Settings"] + + + + + @if (Event.Id > 0) + { + + + + } + + + + + + + + + + + + + + @foreach (var eventFormat in Enum.GetValues()) + { + @Localizer["Administration.Events.Event.EventFormat." + @eventFormat.ToString()] + } + + + + + @foreach (var publishState in Enum.GetValues()) + { + @Localizer["Administration.Events.Event.PublishState." + @publishState.ToString()] + } + + + + + @foreach (var visibilityState in Enum.GetValues()) + { + @Localizer["Administration.Events.Event.VisibilityState." + @visibilityState.ToString()] + } + + + + + + @foreach (var venue in Venues) + { + @venue.Name + } + + + + + + + + + + + + + + + + + + @(Event.Id >= 0 ? Localizer["Administration.Events.Event.Save"] : Localizer["Administration.Events.Event.Create"]) + + + diff --git a/NetEvent/Client/Pages/Administration/Events/EventSettings.razor.cs b/NetEvent/Client/Pages/Administration/Events/EventSettings.razor.cs new file mode 100644 index 00000000..9571a832 --- /dev/null +++ b/NetEvent/Client/Pages/Administration/Events/EventSettings.razor.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using MudBlazor; +using NetEvent.Client.Extensions; +using NetEvent.Client.Services; +using NetEvent.Shared.Dto.Event; +using NetEvent.Shared.Validators; + +namespace NetEvent.Client.Pages.Administration.Events +{ + public partial class EventSettings + { + #region Injects + + [Inject] + private IEventService EventService { get; set; } = default!; + + [Inject] + private ISnackbar Snackbar { get; set; } = default!; + + [Inject] + private IStringLocalizer Localizer { get; set; } = default!; + + [Inject] + private NavigationManager NavigationManager { get; set; } = default!; + + #endregion + + [Parameter] + public EventDto Event { get; set; } = default!; + + [Parameter] + public IList Venues { get; set; } = default!; + + private readonly EventModelFluentValidator _EventValidator = new(); + + private MudForm? _Form = default!; + + private async Task SaveEvent() + { + if (_Form == null) + { + return; + } + + await _Form.Validate(); + + if (_Form.IsValid) + { + var cts = new CancellationTokenSource(); + ServiceResult result; + if (Event.Id >= 0) + { + result = await EventService.UpdateEventAsync(Event, cts.Token); + } + else + { + result = await EventService.CreateEventAsync(Event, cts.Token); + + if (result.Successful && Event?.Id != null) + { + NavigationManager.NavigateTo(UrlHelper.GetEventLink(Event.Id, true)); + } + } + + if (!string.IsNullOrEmpty(result.MessageKey)) + { + Snackbar.Add(Localizer.GetString(result.MessageKey), result.Successful ? Severity.Success : Severity.Error); + } + } + } + } +} diff --git a/NetEvent/Client/Pages/Administration/Events/TicketType.razor b/NetEvent/Client/Pages/Administration/Events/TicketType.razor new file mode 100644 index 00000000..123ea535 --- /dev/null +++ b/NetEvent/Client/Pages/Administration/Events/TicketType.razor @@ -0,0 +1,115 @@ +@page "/administration/event/{eventId}/tickettype/{ticketTypeId}" +@using NetEvent.Client.Extensions; +@using NetEvent.Shared.Dto.Event; + +@if (_Loading) +{ + +} +else if (_EventTicketType != null) +{ + + + + + + @Localizer["Administration.Events.Event.Settings"] + + + + + @if (_EventTicketType.Id > 0) + { + + + + } + + + + + + + + + + + @foreach (var publishState in Enum.GetValues()) + { + @Localizer["Administration.Events.EventTicketType.Currency." + @publishState.ToString()] + } + + + + + + + + + + + + + + + + + + + + @Localizer["Administration.Events.EventTicketType.Cancel"] + + + @(_EventTicketType.Id >= 0 ? Localizer["Administration.Events.EventTicketType.Save"] : Localizer["Administration.Events.EventTicketType.Create"]) + + + +} + diff --git a/NetEvent/Client/Pages/Administration/Events/TicketType.razor.cs b/NetEvent/Client/Pages/Administration/Events/TicketType.razor.cs new file mode 100644 index 00000000..1225a89a --- /dev/null +++ b/NetEvent/Client/Pages/Administration/Events/TicketType.razor.cs @@ -0,0 +1,111 @@ +using System; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using MudBlazor; +using NetEvent.Client.Extensions; +using NetEvent.Client.Services; +using NetEvent.Shared.Dto.Event; +using NetEvent.Shared.Validators; + +namespace NetEvent.Client.Pages.Administration.Events +{ + public partial class TicketType + { + private const int _DayOffset = 2; + + #region Injects + + [Inject] + private IEventService EventService { get; set; } = default!; + + [Inject] + private IStringLocalizer Localizer { get; set; } = default!; + + [Inject] + private NavigationService NavigationService { get; set; } = default!; + + [Inject] + private ISnackbar Snackbar { get; set; } = default!; + + #endregion + + [Parameter] + public string? EventId { get; set; } + + [Parameter] + public string? TicketTypeId { get; set; } + + private readonly EventTicketTypeModelFluentValidator _EventTicketTypeValidator = new(); + private bool _Loading = true; + private EventTicketTypeDto _EventTicketType = default!; + private MudForm? _Form = default!; + private long _EventId; + private CurrencyConverter? CurrencyConverter; + + public double Price { get => _EventTicketType.Currency.ToCurrencyValue(_EventTicketType.Price); set => _EventTicketType.Price = _EventTicketType.Currency.ToCurrencyBaseValue(value); } + + protected override async Task OnInitializedAsync() + { + var cts = new CancellationTokenSource(); + + if (!long.TryParse(EventId, CultureInfo.InvariantCulture, out _EventId)) + { + Snackbar.Add("No event defined!", Severity.Error); + } + + if (long.TryParse(TicketTypeId, CultureInfo.InvariantCulture, out var id)) + { + _EventTicketType = (await EventService.GetEventTicketTypeAsync(id, cts.Token).ConfigureAwait(false)) ?? new EventTicketTypeDto(); + } + else + { + _EventTicketType = new EventTicketTypeDto + { + SellStartDate = DateTime.Today.AddDays(_DayOffset - 1).AddHours(24 - DateTime.Today.Hour), + SellEndDate = DateTime.Today.AddDays(_DayOffset).AddHours(24 - DateTime.Today.Hour), + }; + } + + CurrencyConverter = new CurrencyConverter(_EventTicketType.Currency); + + _Loading = false; + } + + private async Task SaveEventTicketType() + { + if (_Form == null) + { + return; + } + + await _Form.Validate(); + + if (_Form.IsValid) + { + var cts = new CancellationTokenSource(); + ServiceResult result; + if (_EventTicketType.Id >= 0) + { + result = await EventService.UpdateEventTicketTypeAsync(_EventTicketType, cts.Token); + } + else + { + result = await EventService.CreateEventTicketTypeAsync(_EventId, _EventTicketType, cts.Token); + + if (result.Successful && _EventTicketType?.Id != null) + { + NavigationService.NavigateTo(UrlHelper.GetEventLink(_EventTicketType.Id, true)); + } + } + + if (!string.IsNullOrEmpty(result.MessageKey)) + { + Snackbar.Add(Localizer.GetString(result.MessageKey), result.Successful ? Severity.Success : Severity.Error); + } + } + } + } +} diff --git a/NetEvent/Client/Pages/Administration/Events/TicketTypes.razor b/NetEvent/Client/Pages/Administration/Events/TicketTypes.razor new file mode 100644 index 00000000..29417e4f --- /dev/null +++ b/NetEvent/Client/Pages/Administration/Events/TicketTypes.razor @@ -0,0 +1,38 @@ +@using NetEvent.Client.Extensions; +@using NetEvent.Shared.Dto.Event; + + + + + @Localizer["Administration.Events.Event.Tickets"] + + + + + @Localizer["Administration.Events.EventTicketType.Create"] + + + + @Localizer["Administration.Events.Event.Tickets.Name"] + @Localizer["Administration.Events.Event.Tickets.SellStartDate"] + @Localizer["Administration.Events.Event.Tickets.SellEndDate"] + @Localizer["Administration.Events.Event.Tickets.AvailableTickets"] + @Localizer["Administration.Events.Event.Tickets.Price"] + @Localizer["Administration.Events.Event.Tickets.IsGiftable"] + + + + @context.Name + @context.SellStartDate + @context.SellEndDate + @context.AvailableTickets + @context.Currency.ToCurrencyValue(context.Price) @context.Currency.ToSymbol() + @context.IsGiftable + + @Localizer["Administration.Events.EventTicketType.Edit"] + @*@Localizer["Administration.Events.EventTicketType.Create"]*@ + + + + + \ No newline at end of file diff --git a/NetEvent/Client/Pages/Administration/Events/TicketTypes.razor.cs b/NetEvent/Client/Pages/Administration/Events/TicketTypes.razor.cs new file mode 100644 index 00000000..6b28b2ef --- /dev/null +++ b/NetEvent/Client/Pages/Administration/Events/TicketTypes.razor.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Client.Pages.Administration.Events +{ + public partial class TicketTypes + { + #region Injects + + [Inject] + private IStringLocalizer Localizer { get; set; } = default!; + + #endregion + + [Parameter] + public EventDto Event { get; set; } = default!; + } +} diff --git a/NetEvent/Client/Pages/Administration/Settings.razor b/NetEvent/Client/Pages/Administration/Settings.razor index c589d113..b4fd2c04 100644 --- a/NetEvent/Client/Pages/Administration/Settings.razor +++ b/NetEvent/Client/Pages/Administration/Settings.razor @@ -1,6 +1,5 @@ @page "/administration/settings" @attribute [Authorize(Policy = "Admin.System.*")] -@inject Microsoft.Extensions.Localization.IStringLocalizer Localize @using Microsoft.AspNetCore.Authorization @using NetEvent.Client.Components.Administration @@ -10,27 +9,11 @@ - @foreach (var settingsGroup in _SystemSettings.SettingsGroups) { - - @if (_Loading) - { -
@Localize["Administration.Settings.LoadingData"]
- } - else - { - - @foreach (var systemSetting in settingsGroup.Settings) - { - - - - } - - } -
+ } +
\ No newline at end of file diff --git a/NetEvent/Client/Pages/Administration/Settings.razor.cs b/NetEvent/Client/Pages/Administration/Settings.razor.cs index 4dbc49b7..54ae1463 100644 --- a/NetEvent/Client/Pages/Administration/Settings.razor.cs +++ b/NetEvent/Client/Pages/Administration/Settings.razor.cs @@ -1,47 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; -using NetEvent.Client.Services; -using NetEvent.Shared.Config; -using NetEvent.Shared.Dto; +using NetEvent.Shared.Config; namespace NetEvent.Client.Pages.Administration { public partial class Settings { - #region Injects - - [Inject] - private ISystemSettingsDataService SystemSettingsDataService { get; set; } = default!; - - #endregion - private readonly SystemSettings _SystemSettings = SystemSettings.Instance; - private bool _Loading = true; - private IList _OrganizationData = new List(); - private IList _StyleData = new List(); - private IList _AuthenticationData = new List(); - - protected override async Task OnInitializedAsync() - { - var cts = new CancellationTokenSource(); - - _OrganizationData = await SystemSettingsDataService.GetSystemSettingsAsync(SystemSettingGroup.OrganizationData, cts.Token); - _StyleData = await SystemSettingsDataService.GetSystemSettingsAsync(SystemSettingGroup.StyleData, cts.Token); - _AuthenticationData = await SystemSettingsDataService.GetSystemSettingsAsync(SystemSettingGroup.AuthenticationData, cts.Token); - - _Loading = false; - } - - private SystemSettingValueDto? GetValue(string key) - { - return _OrganizationData.FirstOrDefault(x => x.Key.Equals(key, StringComparison.Ordinal)) - ?? _StyleData.FirstOrDefault(x => x.Key.Equals(key, StringComparison.Ordinal)) - ?? _AuthenticationData.FirstOrDefault(x => x.Key.Equals(key, StringComparison.Ordinal)) - ?? new SystemSettingValueDto(key, string.Empty); - } } } diff --git a/NetEvent/Client/Pages/Administration/Users.razor b/NetEvent/Client/Pages/Administration/Users.razor index 8cdd4c49..69622caf 100644 --- a/NetEvent/Client/Pages/Administration/Users.razor +++ b/NetEvent/Client/Pages/Administration/Users.razor @@ -1,17 +1,16 @@ @page "/administration/users" @attribute [Authorize(Policy = "Admin.Users.*")] -@using Microsoft.AspNetCore.Authorization -@using Microsoft.AspNetCore.Identity -@using NetEvent.Client.Components -@using NetEvent.Shared.Dto -@using NetEvent.Shared.Dto.Administration -@using NetEvent.Shared.Policy - -@inject Microsoft.Extensions.Localization.IStringLocalizer Localize +@using Microsoft.AspNetCore.Authorization; +@using Microsoft.AspNetCore.Identity; +@using NetEvent.Client.Components; +@using NetEvent.Shared.Dto; +@using NetEvent.Shared.Dto.Administration; +@using NetEvent.Shared.Policy; +@using System.Net.Http.Json - + - - @Localize["Administration.Users.Title"] + @* + @Localizer["Administration.Users.Title"] - - + *@ + - - - - - + + + + + - + - + @context.Item.Role?.Name @@ -53,7 +53,7 @@ - + @foreach (var role in AllRoles) { @role.Name @@ -62,12 +62,12 @@ - + @* - + *@ - + - - @Localize["Administration.Users.Roles.Title"] +@* + @Localizer["Administration.Users.Roles.Title"] - @@ -114,10 +114,10 @@ @foreach (var policy in Policies.AvailablePolicies) @@ -134,9 +134,9 @@ - + @* - + *@ diff --git a/NetEvent/Client/Pages/Administration/Users.razor.cs b/NetEvent/Client/Pages/Administration/Users.razor.cs index 04f29dc8..7cd17ead 100644 --- a/NetEvent/Client/Pages/Administration/Users.razor.cs +++ b/NetEvent/Client/Pages/Administration/Users.razor.cs @@ -43,7 +43,7 @@ private async Task LoadRoles(CancellationToken cancellationToken) #region Users - public List AllUsers { get; private set; } = new List(); + public IEnumerable AllUsers { get; private set; } = new List(); private string? _UsersSearchString; @@ -98,7 +98,7 @@ private async Task CommittedUserChangesAsync(AdminUserDto updatedUser) #region Roles - public List AllRoles { get; private set; } = new List(); + public IList AllRoles { get; private set; } = new List(); public RoleDto? SelectedRole { get; private set; } diff --git a/NetEvent/Client/Pages/Checkout/CheckoutTicket.razor b/NetEvent/Client/Pages/Checkout/CheckoutTicket.razor new file mode 100644 index 00000000..10bd8ac0 --- /dev/null +++ b/NetEvent/Client/Pages/Checkout/CheckoutTicket.razor @@ -0,0 +1,42 @@ +@page "/checkout/ticket/{ticketType:long}" +@page "/checkout/ticket/{ticketType:long}/{amount:int}" +@using NetEvent.Shared.Dto.Event; + +@if (EventTicketType == null) +{ + +} +else +{ +
+ + + + + c + @EventTicketType.Name + + + @EventTicketType.Currency.ToCurrencyValue(EventTicketType.Price) @EventTicketType.Currency.ToSymbol() + + + + + TODO: Confirm AGB? + + + + @Localizer["Events.Event.Tickets.BuyNow"] + + +
+} + +
+ +@if (_Result != null) +{ + @_Result
@_ResultRefused
+} + +@*
*@ diff --git a/NetEvent/Client/Pages/Checkout/CheckoutTicket.razor.cs b/NetEvent/Client/Pages/Checkout/CheckoutTicket.razor.cs new file mode 100644 index 00000000..319b3e41 --- /dev/null +++ b/NetEvent/Client/Pages/Checkout/CheckoutTicket.razor.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using Microsoft.JSInterop; +using MudBlazor; +using NetEvent.Client.Services; +using NetEvent.Shared.Config; +using NetEvent.Shared.Dto; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Client.Pages.Checkout +{ + public partial class CheckoutTicket + { + #region Injects + + [Inject] + private IEventService EventService { get; set; } = default!; + + [Inject] + private IPaymentService PaymentService { get; set; } = default!; + + [Inject] + private NavigationService NavigationService { get; set; } = default!; + + [Inject] + private ISystemSettingsDataService SettingsService { get; set; } = default!; + + [Inject] + private IStringLocalizer Localizer { get; set; } = default!; + + [Inject] + private IJSRuntime JsRuntime { get; set; } = default!; + + #endregion + + #region Parameters + + [Parameter] + public long TicketType { get; set; } + + [Parameter] + public int? Amount { get; set; } + + #endregion + + private EventTicketTypeDto? EventTicketType; + private CheckoutSessionDto? CheckoutSession; + private IReadOnlyCollection? PaymentMethods; + private PurchaseDto _Purchase; + private Severity _ResultSeverity; + private LocalizedString? _Result; + private LocalizedString? _ResultRefused; + + protected override async Task OnInitializedAsync() + { + var cts = new CancellationTokenSource(); + Amount ??= 1; + + EventTicketType = await EventService.GetEventTicketTypeAsync(TicketType, cts.Token).ConfigureAwait(false); + if (EventTicketType == null) + { + NavigationService.NavigateBack(); + } + } + + private async Task BuyTicketAsync() + { + if (EventTicketType?.Id == null || Amount == null) + { + return; + } + + var cts = new CancellationTokenSource(); + var result = await PaymentService.BuyTicketAsync(EventTicketType.Id.Value, Amount.Value, cts.Token).ConfigureAwait(false); + if (result.Successful && result.ResultData != null) + { + _Purchase = result.ResultData; + var paymentMethods = await PaymentService.LoadPaymentMethodsAsync(EventTicketType.Price, EventTicketType.Currency, cts.Token).ConfigureAwait(false); + if (result.Successful) + { + PaymentMethods = paymentMethods.ResultData; + var clientKey = await SettingsService.GetSystemSettingAsync(SystemSettingGroup.PaymentData, SystemSettings.PaymentData.AdyenClientKey, cts.Token).ConfigureAwait(false); + var paymentMethod = System.Text.Json.JsonSerializer.Serialize(new { paymentMethods = PaymentMethods }, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault }); + await JsRuntime.InvokeVoidAsync("checkout.startPaymentAsync", clientKey?.Value, paymentMethod, DotNetObjectReference.Create(this)).ConfigureAwait(false); + } + } + } + + [JSInvokable] + public async Task MakePayment(JsonElement data) + { + Console.WriteLine(_Purchase.Id); + var dataJson = data.GetRawText(); + var paymentResponse = await PaymentService.MakePaymentAsync(_Purchase.Id, dataJson, CancellationToken.None).ConfigureAwait(false); + + return paymentResponse?.ResultData?.PaymentResponseJson; + } + + [JSInvokable] + public Task MakeDetailsCall(object data) + { + return Task.FromResult(null); + } + + private static class PurchaseResultCode + { + public const int AuthenticationFinished = 0; + public const int AuthenticationNotRequired = 1; + public const int Authorised = 2; + public const int Received = 9; + + public const int Cancelled = 3; + + public const int Error = 5; + public const int ChallengeShopper = 4; + public const int IdentifyShopper = 6; + public const int Pending = 7; + public const int PresentToShopper = 8; + public const int RedirectShopper = 10; + + public const int Refused = 11; + } + + [JSInvokable] + public void ShowResult(int resultCode, string? refusedCode) + { + // https://docs.adyen.com/online-payments/payment-result-codes + _ResultSeverity = resultCode switch + { + PurchaseResultCode.AuthenticationFinished or PurchaseResultCode.AuthenticationNotRequired or PurchaseResultCode.Authorised or PurchaseResultCode.Received => Severity.Success, + PurchaseResultCode.Error => Severity.Error, + PurchaseResultCode.Cancelled or PurchaseResultCode.ChallengeShopper or PurchaseResultCode.IdentifyShopper or PurchaseResultCode.Pending or PurchaseResultCode.PresentToShopper or PurchaseResultCode.RedirectShopper => Severity.Info, + PurchaseResultCode.Refused => Severity.Warning, + _ => Severity.Normal, + }; + _Result = Localizer[$"CheckoutTicket.Result.{resultCode}"]; + if (refusedCode != null) + { + // https://docs.adyen.com/development-resources/refusal-reasons + _ResultRefused = Localizer[$"CheckoutTicket.ResultRefused.{refusedCode}"]; + } + + StateHasChanged(); + } + } +} diff --git a/NetEvent/Client/Pages/Events/Event.razor b/NetEvent/Client/Pages/Events/Event.razor index b7279876..f0dbe047 100644 --- a/NetEvent/Client/Pages/Events/Event.razor +++ b/NetEvent/Client/Pages/Events/Event.razor @@ -9,6 +9,7 @@ @using NetEvent.Shared.Config @using NetEvent.Shared.Dto @using System.Globalization +@using NetEvent.Shared.Dto.Event; @using TinyMCE.Blazor
@@ -51,6 +52,50 @@ } + @if (_Event.TicketTypes != null && _Event.TicketTypes.Any()) + { + @Localize["Administration.Events.Event.Tickets"] + +
+ + @foreach (var ticketType in _Event.TicketTypes.Where(t => t.SellEndDate < DateTime.Now)) + { + + + + @ticketType.Name + + + @ticketType.Currency.ToCurrencyValue(ticketType.Price) @ticketType.Currency.ToSymbol() + + + + + + @Localize["Events.Event.Tickets.Available", "TODO remainingTickets / " + @ticketType.AvailableTickets] + + + + @if (ticketType.SellStartDate >= DateTime.Now) + { + @Localize["Events.Event.Tickets.AvailableFrom", ticketType.SellStartDate] + } + else + { + @Localize["Events.Event.Tickets.AvailableUntil", ticketType.SellEndDate] + } + + + @Localize["Events.Event.Tickets.Buy"] + + + } + +
+ + + } + @if (_Event.Description != null) { @((MarkupString)_Event.Description) diff --git a/NetEvent/Client/Pages/Events/Event.razor.cs b/NetEvent/Client/Pages/Events/Event.razor.cs index d1619bbd..98011c33 100644 --- a/NetEvent/Client/Pages/Events/Event.razor.cs +++ b/NetEvent/Client/Pages/Events/Event.razor.cs @@ -25,6 +25,9 @@ public partial class Event [Inject] private IStringLocalizer Localizer { get; set; } = default!; + [Inject] + private IPaymentService CartService { get; set; } = default!; + #endregion [Parameter] @@ -56,5 +59,13 @@ private static Color GetStateColor(PublishStateDto state) _ => throw new($"PublishState {state} is not supported!"), }; } + + private Task BuyTicketAsync(EventTicketTypeDto eventTicketType) + { + // /checkout/ticket/{tickettypeid}/{count} + NavigationManager.NavigateTo($"checkout/ticket/{eventTicketType.Id}"); + return Task.CompletedTask; + //CartService.AddToCart(eventTicketType); + } } } diff --git a/NetEvent/Client/Program.cs b/NetEvent/Client/Program.cs index d02e6986..fd9c499b 100644 --- a/NetEvent/Client/Program.cs +++ b/NetEvent/Client/Program.cs @@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Net; using System.Threading.Tasks; +using Blazored.LocalStorage; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Authentication; @@ -39,6 +40,9 @@ private static async Task Main(string[] args) builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); + + builder.Services.AddSingleton(); builder.Services.AddHttpClient(Constants.BackendApiHttpClientName) .ConfigureHttpClient(client => @@ -70,9 +74,11 @@ private static async Task Main(string[] args) config.SnackbarConfiguration.SnackbarVariant = Variant.Filled; #pragma warning restore S109 }); + builder.Services.AddBlazoredLocalStorage(); var app = builder.Build(); await app.SetDefaultCultureAsync(); + await app.InitializeNavigationService(); await app.RunAsync(); } diff --git a/NetEvent/Client/Resources/App.resx b/NetEvent/Client/Resources/App.resx index 7a003f8d..3f7980d3 100644 --- a/NetEvent/Client/Resources/App.resx +++ b/NetEvent/Client/Resources/App.resx @@ -471,12 +471,6 @@ Start date - - Error deleting event - - - Event deleted successfully - Edit @@ -678,6 +672,123 @@ Hide name of organization in navbar + + Error creating + + + Created successfully + + + Error deleting + + + Deleted successfully + + + Error updating + + + Updated successfully + + + Tickets + + + Available Tickets + + + Create Ticket Type + + + Currency + + + Euro (€) + + + Is giftable + + + Name + + + Price + + + Sell End + + + Sell Start + + + Available Tickets + + + Is Giftable + + + Name + + + Price + + + Sell End + + + Sell Start + + + Sort by + + + Cancel + + + Edit + + + Id + + + Save + + + Buy + + + Available from {0} + + + Available until {0} + + + Buy now + + + available {0} + + + Payment + + + https://docs.adyen.com/development-resources/api-credentials#generate-api-key + + + Adyen Api Key + + + https://docs.adyen.com/development-resources/client-side-authentication#get-your-client-key + + + Adyen Client Key + + + https://ca-test.adyen.com/ca/ca/accounts/show.shtml?accountTypeCode=MerchantAccount + + + Adyen Merchant Account + Event not found diff --git a/NetEvent/Client/Services/EventService.cs b/NetEvent/Client/Services/EventService.cs index 0a630fe4..ae9d43ba 100644 --- a/NetEvent/Client/Services/EventService.cs +++ b/NetEvent/Client/Services/EventService.cs @@ -35,14 +35,14 @@ public async Task CreateEventAsync(EventDto eventDto, Cancellatio eventDto.Id = long.Parse(await response.Content.ReadAsStringAsync(cancellationToken), CultureInfo.InvariantCulture); - return ServiceResult.Success("EventService.AddEventAsync.Success"); + return ServiceResult.Success("EventService.AddAsync.Success"); } catch (Exception ex) { _Logger.LogError(ex, "Unable to create event in backend."); } - return ServiceResult.Error("EventService.AddEventAsync.Error"); + return ServiceResult.Error("EventService.AddAsync.Error"); } public async Task GetEventAsync(string slug, CancellationToken cancellationToken) @@ -128,14 +128,14 @@ public async Task UpdateEventAsync(EventDto eventDto, Cancellatio response.EnsureSuccessStatusCode(); - return ServiceResult.Success("EventService.UpdateEventAsync.Success"); + return ServiceResult.Success("EventService.UpdateAsync.Success"); } catch (Exception ex) { _Logger.LogError(ex, "Unable to update event in backend."); } - return ServiceResult.Error("EventService.UpdateEventAsync.Error"); + return ServiceResult.Error("EventService.UpdateAsync.Error"); } public async Task DeleteEventAsync(long id, CancellationToken cancellationToken) @@ -148,14 +148,96 @@ public async Task DeleteEventAsync(long id, CancellationToken can response.EnsureSuccessStatusCode(); - return ServiceResult.Success("EventService.DeleteEventAsync.Success"); + return ServiceResult.Success("EventService.DeleteAsync.Success"); } catch (Exception ex) { _Logger.LogError(ex, "Unable to delete event in backend."); } - return ServiceResult.Error("EventService.DeleteEventAsync.Error"); + return ServiceResult.Error("EventService.DeleteAsync.Error"); } - } + + public async Task CreateEventTicketTypeAsync(long eventId, EventTicketTypeDto eventTicketTypeDto, CancellationToken cancellationToken) + { + try + { + var client = _HttpClientFactory.CreateClient(Constants.BackendApiHttpClientName); + + var response = await client.PostAsJsonAsync($"api/events/tickettype/{eventId}", eventTicketTypeDto, cancellationToken); + response.EnsureSuccessStatusCode(); + + eventTicketTypeDto.Id = long.Parse(await response.Content.ReadAsStringAsync(cancellationToken), CultureInfo.InvariantCulture); + + return ServiceResult.Success("EventService.AddAsync.Success"); + } + catch (Exception ex) + { + _Logger.LogError(ex, "Unable to create eventTicketType in backend."); + } + + return ServiceResult.Error("EventService.AddAsync.Error"); + } + + public async Task UpdateEventTicketTypeAsync(EventTicketTypeDto eventTicketTypeDto, CancellationToken cancellationToken) + { + try + { + var client = _HttpClientFactory.CreateClient(Constants.BackendApiHttpClientName); + + var response = await client.PutAsJsonAsync($"api/events/tickettype/{eventTicketTypeDto.Id}", eventTicketTypeDto, cancellationToken); + response.EnsureSuccessStatusCode(); + + return ServiceResult.Success("EventService.UpdateAsync.Success"); + } + catch (Exception ex) + { + _Logger.LogError(ex, "Unable to update eventTicketType in backend."); + } + + return ServiceResult.Error("EventService.UpdateAsync.Error"); + } + + public async Task DeleteEventTicketTypeAsync(long id, CancellationToken cancellationToken) + { + try + { + var client = _HttpClientFactory.CreateClient(Constants.BackendApiHttpClientName); + + var response = await client.DeleteAsync($"api/events/tickettype/{id}", cancellationToken); + response.EnsureSuccessStatusCode(); + + return ServiceResult.Success("EventService.DeleteAsync.Success"); + } + catch (Exception ex) + { + _Logger.LogError(ex, "Unable to delete eventTicketType in backend."); + } + + return ServiceResult.Error("EventService.DeleteAsync.Error"); + } + + public async Task GetEventTicketTypeAsync(long id, CancellationToken cancellationToken) + { + try + { + var client = _HttpClientFactory.CreateClient(Constants.BackendApiHttpClientName); + + var eventTicketTypeDto = await client.GetFromJsonAsync($"/api/events/tickettype/{id}", cancellationToken).ConfigureAwait(false); + + if (eventTicketTypeDto == null) + { + _Logger.LogError("Unable to get eventtickettype data from backend"); + return null; + } + + return eventTicketTypeDto; + } + catch (Exception ex) + { + _Logger.LogError(ex, "Unable to get eventtickettype data from backend"); + return null; + } + } + } } diff --git a/NetEvent/Client/Services/IEventService.cs b/NetEvent/Client/Services/IEventService.cs index 4e5ef235..5fc97c96 100644 --- a/NetEvent/Client/Services/IEventService.cs +++ b/NetEvent/Client/Services/IEventService.cs @@ -20,5 +20,11 @@ public interface IEventService Task UpdateEventAsync(EventDto eventDto, CancellationToken cancellationToken); Task CreateEventAsync(EventDto eventDto, CancellationToken cancellationToken); + + Task GetEventTicketTypeAsync(long id, CancellationToken cancellationToken); + + Task UpdateEventTicketTypeAsync(EventTicketTypeDto eventTicketTypeDto, CancellationToken cancellationToken); + + Task CreateEventTicketTypeAsync(long eventId, EventTicketTypeDto eventTicketTypeDto, CancellationToken cancellationToken); } } diff --git a/NetEvent/Client/Services/IPaymentService.cs b/NetEvent/Client/Services/IPaymentService.cs new file mode 100644 index 00000000..7fc1ca8b --- /dev/null +++ b/NetEvent/Client/Services/IPaymentService.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using NetEvent.Shared.Dto; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Client.Services +{ + public interface IPaymentService + { + Task> BuyTicketAsync(long id, int amount, CancellationToken cancellationToken); + + Task LoadCart(string cartId); + + Task?>> LoadPaymentMethodsAsync(long amount, CurrencyDto currency, CancellationToken cancellationToken); + + Task> MakePaymentAsync(string purchaseId, string paymentDataJson, CancellationToken cancellationToken); + } +} diff --git a/NetEvent/Client/Services/NavigationService.cs b/NetEvent/Client/Services/NavigationService.cs new file mode 100644 index 00000000..d2f82fc9 --- /dev/null +++ b/NetEvent/Client/Services/NavigationService.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Routing; + +namespace NetEvent.Client.Services +{ + public sealed class NavigationService : IDisposable + { + private const int MinHistorySize = 256; + private const int AdditionalHistorySize = 64; + + private readonly NavigationManager _NavigationManager; + private readonly List _History; + + public NavigationService(NavigationManager navigationManager) + { + _NavigationManager = navigationManager; + _History = new List(MinHistorySize + AdditionalHistorySize) + { + _NavigationManager.Uri + }; + _NavigationManager.LocationChanged += OnLocationChanged; + } + + /// + /// Navigates to the specified url. + /// + /// The destination url (relative or absolute). + public void NavigateTo(string url) + { + _NavigationManager.NavigateTo(url); + } + + /// + /// Returns true if it is possible to navigate to the previous url. + /// + public bool CanNavigateBack => _History.Count >= 2; + + /// + /// Navigates to the previous url if possible or does nothing if it is not. + /// + public void NavigateBack() + { + if (!CanNavigateBack) + { + return; + } + + var backPageUrl = _History[^2]; + _History.RemoveRange(_History.Count - 2, 2); + _NavigationManager.NavigateTo(backPageUrl); + } + + private void OnLocationChanged(object sender, LocationChangedEventArgs e) + { + EnsureSize(); + _History.Add(e.Location); + } + + private void EnsureSize() + { + if (_History.Count < MinHistorySize + AdditionalHistorySize) + { + return; + } + + _History.RemoveRange(0, _History.Count - MinHistorySize); + } + + #region Implementation of Dispose + + private void Dispose(bool disposing) + { + if (disposing) + { + _NavigationManager.LocationChanged -= OnLocationChanged; + } + } + + public void Dispose() + { + Dispose(true); + } + + #endregion + } +} diff --git a/NetEvent/Client/Services/NavigationServiceExtension.cs b/NetEvent/Client/Services/NavigationServiceExtension.cs new file mode 100644 index 00000000..4d86d6f2 --- /dev/null +++ b/NetEvent/Client/Services/NavigationServiceExtension.cs @@ -0,0 +1,18 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using Microsoft.Extensions.DependencyInjection; + +namespace NetEvent.Client.Services +{ + public static class NavigationServiceExtension + { + public static Task InitializeNavigationService(this WebAssemblyHost app) + { + var navigationService = app.Services.GetRequiredService(); + return navigationService == null + ? throw new NotSupportedException("Start without NavigationServce is not possible!") + : Task.CompletedTask; + } + } +} diff --git a/NetEvent/Client/Services/PaymentService.cs b/NetEvent/Client/Services/PaymentService.cs new file mode 100644 index 00000000..de827bf5 --- /dev/null +++ b/NetEvent/Client/Services/PaymentService.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Json; +using System.Threading; +using System.Threading.Tasks; +using Blazored.LocalStorage; +using Microsoft.Extensions.Logging; +using NetEvent.Shared.Dto; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Client.Services +{ + public class PaymentService : IPaymentService + { + private const string _CartKey = "cart"; + + private readonly IHttpClientFactory _HttpClientFactory; + private readonly ILogger _Logger; + private readonly ILocalStorageService _LocalStorage; + + public PaymentService(ILocalStorageService localStorage, IHttpClientFactory httpClientFactory, ILogger logger) + { + _LocalStorage = localStorage; + _HttpClientFactory = httpClientFactory; + _Logger = logger; + } + + public async Task LoadCart(string cartId) + { + if (await _LocalStorage.ContainKeyAsync(cartId).ConfigureAwait(false)) + { + return await _LocalStorage.GetItemAsync(_CartKey); + } + + var cart = new CartDto(); + await _LocalStorage.SetItemAsync(_CartKey, cart); + return cart; + } + + public async Task> BuyTicketAsync(long id, int amount, CancellationToken cancellationToken) + { + try + { + var ticketCart = new CartDto { CartEntries = new[] { new CartEntryDto { TicketId = id, Amount = amount } } }; + + var client = _HttpClientFactory.CreateClient(Constants.BackendApiHttpClientName); + + var response = await client.PostAsJsonAsync($"api/payment/checkout/buy", ticketCart, cancellationToken); + response.EnsureSuccessStatusCode(); + + var sessionResponse = await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + + return ServiceResult.Success(sessionResponse, "EventService.AddAsync.Success"); + } + catch (Exception ex) + { + _Logger.LogError(ex, "Unable to create eventTicketType in backend."); + } + + return ServiceResult.Error("EventService.AddAsync.Error"); + } + + public async Task?>> LoadPaymentMethodsAsync(long amount, CurrencyDto currency, CancellationToken cancellationToken) + { + try + { + var client = _HttpClientFactory.CreateClient(Constants.BackendApiHttpClientName); + + var response = await client.GetFromJsonAsync>($"api/payment/paymentmethods/{amount}/{currency}", cancellationToken); + + return ServiceResult?>.Success(response); + } + catch (Exception ex) + { + _Logger.LogError(ex, "Unable to create eventTicketType in backend."); + } + + return ServiceResult?>.Error("PaymentService.LoadPaymentMethodsAsync.Error"); + } + + public async Task> MakePaymentAsync(string purchaseId, string paymentDataJson, CancellationToken cancellationToken) + { + try + { + var client = _HttpClientFactory.CreateClient(Constants.BackendApiHttpClientName); + + var response = await client.PostAsJsonAsync($"api/payment/checkout/{purchaseId}/payments", paymentDataJson, cancellationToken); + response.EnsureSuccessStatusCode(); + var paymentResponse = await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + return ServiceResult.Success(paymentResponse); + } + catch (Exception ex) + { + _Logger.LogError(ex, "Unable to create eventTicketType in backend."); + } + + return ServiceResult.Error("PaymentService.LoadPaymentMethodsAsync.Error"); + } + } +} diff --git a/NetEvent/Client/wwwroot/index.html b/NetEvent/Client/wwwroot/index.html index 7cc649be..26b56a3f 100644 --- a/NetEvent/Client/wwwroot/index.html +++ b/NetEvent/Client/wwwroot/index.html @@ -29,8 +29,15 @@ - - + + + diff --git a/NetEvent/Directory.Build.props b/NetEvent/Directory.Build.props new file mode 100644 index 00000000..59690008 --- /dev/null +++ b/NetEvent/Directory.Build.props @@ -0,0 +1,8 @@ + + + net8.0 + + enable + true + + \ No newline at end of file diff --git a/NetEvent/Server.Tests/EventModuleTest.cs b/NetEvent/Server.Tests/EventModuleTest.cs index e06397d9..9cb77ea1 100644 --- a/NetEvent/Server.Tests/EventModuleTest.cs +++ b/NetEvent/Server.Tests/EventModuleTest.cs @@ -1,10 +1,13 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Linq; using System.Net.Http; using System.Net.Http.Json; using System.Threading.Tasks; using Bogus; +using NetEvent.Shared; using NetEvent.Shared.Dto.Event; using NetEvent.TestHelper; using Xunit; @@ -138,5 +141,84 @@ public Task EventModuleTest_DeleteEventRoute_Test() }, true); } + + [Fact] + public Task EventModuleTest_PostEventTicketTypeRoute_Test() + { + // Arrange + return RunWithFakeEvents(async fakeEvents => + { + var fakeEventTicketType = Fakers.EventTicketTypeFaker(fakeEvents).Generate(); + + // Act + var postResult = await Client.PostAsJsonAsync($"/api/events/tickettype/{fakeEventTicketType.EventId}", fakeEventTicketType.ToEventTicketTypeDto()).ConfigureAwait(false); + postResult.EnsureSuccessStatusCode(); + var updatedEvent = await Client.GetFromJsonAsync($"/api/events/{fakeEventTicketType.EventId}").ConfigureAwait(false); + + // Assert + Assert.NotNull(updatedEvent?.TicketTypes); + Assert.Single(updatedEvent.TicketTypes); + Assert.Equal(fakeEventTicketType.Name, updatedEvent.TicketTypes.First().Name, StringComparer.Ordinal); + }, + true); + } + + [Fact] + public Task EventModuleTest_PutEventTicketTypeRoute_Test() + { + // Arrange + return RunWithFakeEvents(async fakeEvents => + { + var faker = new Faker(); + var fakeEventTicketType = Fakers.EventTicketTypeFaker(fakeEvents).Generate(); + + var postResult = await Client.PostAsJsonAsync($"/api/events/tickettype/{fakeEventTicketType.EventId}", fakeEventTicketType.ToEventTicketTypeDto()).ConfigureAwait(false); + postResult.EnsureSuccessStatusCode(); + if (int.TryParse(await postResult.Content.ReadAsStringAsync().ConfigureAwait(false), CultureInfo.InvariantCulture, out var newId)) + { + fakeEventTicketType.Id = newId; + } + + fakeEventTicketType.Name = faker.Name.FullName(); + + // Act + var putResult = await Client.PutAsJsonAsync($"/api/events/tickettype/{fakeEventTicketType.Id}", fakeEventTicketType.ToEventTicketTypeDto()).ConfigureAwait(false); + putResult.EnsureSuccessStatusCode(); + var updatedEvent = await Client.GetFromJsonAsync($"/api/events/{fakeEventTicketType.EventId}").ConfigureAwait(false); + + // Assert + Assert.NotNull(updatedEvent?.TicketTypes); + Assert.Single(updatedEvent.TicketTypes); + Assert.Equal(fakeEventTicketType.Name, updatedEvent.TicketTypes.First().Name, StringComparer.Ordinal); + }, + true); + } + + [Fact] + public Task EventModuleTest_DeleteEventTicketTypeRoute_Test() + { + // Arrange + return RunWithFakeEvents(async fakeEvents => + { + var fakeEventTicketType = Fakers.EventTicketTypeFaker(fakeEvents).Generate(); + + var postResult = await Client.PostAsJsonAsync($"/api/events/tickettype/{fakeEventTicketType.EventId}", fakeEventTicketType.ToEventTicketTypeDto()).ConfigureAwait(false); + postResult.EnsureSuccessStatusCode(); + if (int.TryParse(await postResult.Content.ReadAsStringAsync().ConfigureAwait(false), CultureInfo.InvariantCulture, out var newId)) + { + fakeEventTicketType.Id = newId; + } + + // Act + var deleteResult = await Client.DeleteAsync($"/api/events/tickettype/{fakeEventTicketType.Id}").ConfigureAwait(false); + deleteResult.EnsureSuccessStatusCode(); + var updatedEvent = await Client.GetFromJsonAsync($"/api/events/{fakeEventTicketType.EventId}").ConfigureAwait(false); + + // Assert + Assert.NotNull(updatedEvent?.TicketTypes); + Assert.Empty(updatedEvent.TicketTypes); + }, + true); + } } } diff --git a/NetEvent/Server.Tests/NetEvent.Server.Tests.csproj b/NetEvent/Server.Tests/NetEvent.Server.Tests.csproj index 8baf4003..0fa831e9 100644 --- a/NetEvent/Server.Tests/NetEvent.Server.Tests.csproj +++ b/NetEvent/Server.Tests/NetEvent.Server.Tests.csproj @@ -15,7 +15,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/NetEvent/Server.Tests/RolesModuleTest.cs b/NetEvent/Server.Tests/RolesModuleTest.cs index c10a452d..c05aeabc 100644 --- a/NetEvent/Server.Tests/RolesModuleTest.cs +++ b/NetEvent/Server.Tests/RolesModuleTest.cs @@ -107,7 +107,7 @@ public async Task RolesModuleTest_PostRoleRoute_Test() Assert.NotNull(loadedRoles); Assert.Equal(1, loadedRoles?.Count); - var claims = loadedRoles?.First().Claims; + var claims = loadedRoles?[0].Claims; Assert.NotNull(claims); if (claims != null) { @@ -163,7 +163,7 @@ public async Task RolesModuleTest_DeleteRoleRoute_Test() Assert.NotNull(roles); Assert.Equal(roleCount, roles?.Count); - var response = await Client.DeleteAsync($"api/roles/{roles?.First().Id}"); + var response = await Client.DeleteAsync($"api/roles/{roles?[0].Id}"); response.EnsureSuccessStatusCode(); roles = await Client.GetFromJsonAsync>("/api/roles"); diff --git a/NetEvent/Server.Tests/SystemModuleTest.cs b/NetEvent/Server.Tests/SystemModuleTest.cs index 67ed2e68..b40772cf 100644 --- a/NetEvent/Server.Tests/SystemModuleTest.cs +++ b/NetEvent/Server.Tests/SystemModuleTest.cs @@ -174,11 +174,11 @@ public async Task GetSystemInfoVersionsSetted_Test() Assert.NotNull(response.Versions); Assert.NotEmpty(response.Health); Assert.NotEmpty(response.Versions); - Assert.Equal("TEST", response.Versions?.Find(x => x.Component.Equals("BUILDNODE", StringComparison.OrdinalIgnoreCase))?.Version); - Assert.Equal("TEST", response.Versions?.Find(x => x.Component.Equals("BUILDID", StringComparison.OrdinalIgnoreCase))?.Version); - Assert.Equal("TEST", response.Versions?.Find(x => x.Component.Equals("BUILDNUMBER", StringComparison.OrdinalIgnoreCase))?.Version); - Assert.Equal("TEST", response.Versions?.Find(x => x.Component.Equals("SOURCE_COMMIT", StringComparison.OrdinalIgnoreCase))?.Version); - Assert.Equal(Assembly.GetEntryAssembly()?.GetCustomAttribute()?.InformationalVersion, response.Versions?.Find(x => x.Component.Equals("NETEVENT", StringComparison.OrdinalIgnoreCase))?.Version); + Assert.Equal("TEST", response.Versions?.FirstOrDefault(x => x.Component.Equals("BUILDNODE", StringComparison.OrdinalIgnoreCase))?.Version); + Assert.Equal("TEST", response.Versions?.FirstOrDefault(x => x.Component.Equals("BUILDID", StringComparison.OrdinalIgnoreCase))?.Version); + Assert.Equal("TEST", response.Versions?.FirstOrDefault(x => x.Component.Equals("BUILDNUMBER", StringComparison.OrdinalIgnoreCase))?.Version); + Assert.Equal("TEST", response.Versions?.FirstOrDefault(x => x.Component.Equals("SOURCE_COMMIT", StringComparison.OrdinalIgnoreCase))?.Version); + Assert.Equal(Assembly.GetEntryAssembly()?.GetCustomAttribute()?.InformationalVersion, response.Versions?.FirstOrDefault(x => x.Component.Equals("NETEVENT", StringComparison.OrdinalIgnoreCase))?.Version); } [Fact] @@ -198,10 +198,10 @@ public async Task GetSystemInfoVersionsNotSetted_Test() Assert.NotNull(response.Versions); Assert.NotEmpty(response.Versions); Assert.NotEmpty(response.Versions); - Assert.Equal("dev", response.Versions?.Find(x => x.Component.Equals("BUILDNODE", StringComparison.OrdinalIgnoreCase))?.Version); - Assert.Equal("dev", response.Versions?.Find(x => x.Component.Equals("BUILDID", StringComparison.OrdinalIgnoreCase))?.Version); - Assert.Equal("dev", response.Versions?.Find(x => x.Component.Equals("BUILDNUMBER", StringComparison.OrdinalIgnoreCase))?.Version); - Assert.Equal("dev", response.Versions?.Find(x => x.Component.Equals("SOURCE_COMMIT", StringComparison.OrdinalIgnoreCase))?.Version); + Assert.Equal("dev", response.Versions?.FirstOrDefault(x => x.Component.Equals("BUILDNODE", StringComparison.OrdinalIgnoreCase))?.Version); + Assert.Equal("dev", response.Versions?.FirstOrDefault(x => x.Component.Equals("BUILDID", StringComparison.OrdinalIgnoreCase))?.Version); + Assert.Equal("dev", response.Versions?.FirstOrDefault(x => x.Component.Equals("BUILDNUMBER", StringComparison.OrdinalIgnoreCase))?.Version); + Assert.Equal("dev", response.Versions?.FirstOrDefault(x => x.Component.Equals("SOURCE_COMMIT", StringComparison.OrdinalIgnoreCase))?.Version); } [Fact] @@ -250,7 +250,7 @@ public Task PostGetDeleteSystemImagesHandler_Success_Test() Assert.NotNull(images); Assert.NotEmpty(images!); - var response = await Client.DeleteAsync($"api/system/image/{images!.First().Image.Id}"); + var response = await Client.DeleteAsync($"api/system/image/{images![0].Image.Id}"); response.EnsureSuccessStatusCode(); images = await Client.GetFromJsonAsync>("/api/system/image/all"); diff --git a/NetEvent/Server.Tests/UsersModuleTest.cs b/NetEvent/Server.Tests/UsersModuleTest.cs index c526b080..caf1abbc 100644 --- a/NetEvent/Server.Tests/UsersModuleTest.cs +++ b/NetEvent/Server.Tests/UsersModuleTest.cs @@ -138,7 +138,7 @@ public async Task UsersModuleTest_PutUserRoleRoute_Test() var roles = await userManager.GetRolesAsync(applicationUser); // Assert - Assert.Equal(1, roles.Count); + Assert.Single(roles); Assert.Equal(applicationRole.Name, roles[0]); } } diff --git a/NetEvent/Server/Data/ApplicationDbContext.cs b/NetEvent/Server/Data/ApplicationDbContext.cs index 67c0b767..9ffc5818 100644 --- a/NetEvent/Server/Data/ApplicationDbContext.cs +++ b/NetEvent/Server/Data/ApplicationDbContext.cs @@ -34,6 +34,12 @@ public ApplicationDbContext(DbContextOptions options, IReadOnlyCollection Venues => Set(); + public virtual DbSet Purchases => Set(); + + public virtual DbSet TicketPurchases => Set(); + + public virtual DbSet Tickets => Set(); + public override EntityEntry Add(TEntity entity) { return base.Add(entity); diff --git a/NetEvent/Server/Data/Events/EventManager.cs b/NetEvent/Server/Data/Events/EventManager.cs index a96727ae..109fca9f 100644 --- a/NetEvent/Server/Data/Events/EventManager.cs +++ b/NetEvent/Server/Data/Events/EventManager.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -152,5 +153,64 @@ public async Task UpdateVenueAsync(Venue venueToUpdate) _Logger.LogError("Error updating Venue {name}", venueToUpdate.Name); return EventResult.Failed(new EventError()); } + + public async Task CreateTicketAsync(EventTicketType ticketToCreate) + { + var maxId = await _DbContext.Tickets.MaxAsync(x => x.Id); + ticketToCreate.Id = maxId.HasValue ? maxId.Value + 1 : 1; + ticketToCreate.Slug = _SlugHelper.GenerateSlug(ticketToCreate.Name); + + var addResult = await _DbContext.Tickets.AddAsync(ticketToCreate, CancellationToken); + if (addResult.State == EntityState.Added) + { + await _DbContext.SaveChangesAsync(); + _Logger.LogInformation("Successfully created Ticket {name}", ticketToCreate.Name); + return EventResult.Success; + } + + _Logger.LogError("Error creating Ticket {name}", ticketToCreate.Name); + return EventResult.Failed(new EventError()); + } + + public async Task DeleteTicketAsync(long ticketId) + { + var ticketToDelete = await _DbContext.Tickets.FindAsync(ticketId); + if (ticketToDelete == null) + { + return EventResult.Failed(new EventError { Description = $"Ticket with Id '{ticketId}' was not found" }); + } + + _DbContext.Tickets.Remove(ticketToDelete); + await _DbContext.SaveChangesAsync(); + + return EventResult.Success; + } + + public async Task UpdateTicketAsync(EventTicketType ticketToUpdate) + { + var oldTicketType = await _DbContext.Tickets.Where(t => t.Id == ticketToUpdate.Id).Include(t => t.Event).FirstAsync(CancellationToken).ConfigureAwait(false); + if (oldTicketType == null) + { + _Logger.LogError("Error updating Ticket {name} with {id}. It was not found.", ticketToUpdate.Name, ticketToUpdate.Id); + return EventResult.Failed(new EventError()); + } + + ticketToUpdate.Slug = _SlugHelper.GenerateSlug(ticketToUpdate.Name); + ticketToUpdate.EventId = oldTicketType.EventId; + ticketToUpdate.Event = oldTicketType.Event; + _DbContext.Entry(oldTicketType).State = EntityState.Detached; + + var result = _DbContext.Tickets.Update(ticketToUpdate); + + if (result.State == EntityState.Modified) + { + await _DbContext.SaveChangesAsync(); + _Logger.LogInformation("Successfully updated Ticket {name}", ticketToUpdate.Name); + return EventResult.Success; + } + + _Logger.LogError("Error updating Ticket {name}", ticketToUpdate.Name); + return EventResult.Failed(new EventError()); + } } } diff --git a/NetEvent/Server/Data/Events/IEventManager.cs b/NetEvent/Server/Data/Events/IEventManager.cs index 6119a57a..ef9c70e0 100644 --- a/NetEvent/Server/Data/Events/IEventManager.cs +++ b/NetEvent/Server/Data/Events/IEventManager.cs @@ -21,5 +21,11 @@ public interface IEventManager Task DeleteVenueAsync(long venueId); Task UpdateVenueAsync(Venue venueToUpdate); + + Task CreateTicketAsync(EventTicketType ticketToCreate); + + Task DeleteTicketAsync(long ticketId); + + Task UpdateTicketAsync(EventTicketType ticketToUpdate); } } diff --git a/NetEvent/Server/Data/IPaymentManager.cs b/NetEvent/Server/Data/IPaymentManager.cs new file mode 100644 index 00000000..b103697b --- /dev/null +++ b/NetEvent/Server/Data/IPaymentManager.cs @@ -0,0 +1,18 @@ +using System.Security.Claims; +using System.Threading.Tasks; +using Adyen.Model.Checkout; +using NetEvent.Server.Models; +using NetEvent.Shared.Dto; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Server.Data +{ + public interface IPaymentManager + { + Task GetPaymentMethodsAsync(long amount, CurrencyDto currency); + + Task PurchaseAsync(CartDto cart, ClaimsPrincipal claimsPrincipal); + + Task SubmitDropInEventDataAsync(ClaimsPrincipal claimsPrincipal, string purchaseId, string paymentMethodData); + } +} diff --git a/NetEvent/Server/Data/PaymentManager.cs b/NetEvent/Server/Data/PaymentManager.cs new file mode 100644 index 00000000..e0e9c1ca --- /dev/null +++ b/NetEvent/Server/Data/PaymentManager.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Adyen; +using Adyen.Model.Checkout; +using Adyen.Service.Checkout; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using NetEvent.Server.Helpers; +using NetEvent.Server.Models; +using NetEvent.Shared; +using NetEvent.Shared.Config; +using NetEvent.Shared.Dto; +using NetEvent.Shared.Dto.Event; +using Newtonsoft.Json; + +namespace NetEvent.Server.Data +{ + public class PaymentManager : IPaymentManager + { + private readonly ApplicationDbContext _DbContext; + + private readonly NetEventUserManager _UserManager; + + private readonly ILogger _Logger; + + public PaymentManager(ApplicationDbContext dbContext, NetEventUserManager userManager, ILogger logger) + { + _DbContext = dbContext; + _UserManager = userManager; + _Logger = logger; + } + + public async Task GetPaymentMethodsAsync(long amount, CurrencyDto currency) + { + var merchantAccount = await _DbContext.SystemSettingValues.FindAsync(SystemSettings.PaymentData.AdyenMerchantAccount).ConfigureAwait(false); + var apiKey = await _DbContext.SystemSettingValues.FindAsync(SystemSettings.PaymentData.AdyenApiKey).ConfigureAwait(false); + + if (string.IsNullOrEmpty(merchantAccount?.SerializedValue)) + { + // TODO Error + return null; + } + + if (string.IsNullOrEmpty(apiKey?.SerializedValue)) + { + // TODO Error + return null; + } + + var config = new Config + { + XApiKey = apiKey.SerializedValue, + Environment = Adyen.Model.Environment.Test + }; + var client = new Adyen.Client(config); + var checkout = new PaymentsService(client); + + var paymentMethodsRequest = new PaymentMethodsRequest(merchantAccount: merchantAccount.SerializedValue) + { + CountryCode = new RegionInfo(CultureInfo.CurrentUICulture.LCID).TwoLetterISORegionName, + ShopperLocale = CultureInfo.CurrentUICulture.Name, + Amount = new Amount(currency.To3DigitIso(), amount), + Channel = PaymentMethodsRequest.ChannelEnum.Web + }; + + var paymentMethodsResponse = checkout.PaymentMethods(paymentMethodsRequest); + return paymentMethodsResponse; + } + + public async Task PurchaseAsync(CartDto cart, ClaimsPrincipal claimsPrincipal) + { + var merchantAccount = await _DbContext.SystemSettingValues.FindAsync(SystemSettings.PaymentData.AdyenMerchantAccount).ConfigureAwait(false); + var apiKey = await _DbContext.SystemSettingValues.FindAsync(SystemSettings.PaymentData.AdyenApiKey).ConfigureAwait(false); + + if (string.IsNullOrEmpty(merchantAccount?.SerializedValue)) + { + // TODO Error + return null; + } + + if (string.IsNullOrEmpty(apiKey?.SerializedValue)) + { + // TODO Error + return null; + } + + var purchase = await CreatePurchaseAsync(cart, claimsPrincipal).ConfigureAwait(false); + + if (purchase == null) + { + // TODO Error + return null; + } + + var currencyGroup = purchase.TicketPurchases.GroupBy(x => x.Currency); + if (currencyGroup.Count() > 1) + { + // TODO Error + return null; + } + + await _DbContext.Purchases.AddAsync(purchase).ConfigureAwait(false); + await _DbContext.SaveChangesAsync().ConfigureAwait(false); + + return purchase; + } + + public async Task SubmitDropInEventDataAsync(ClaimsPrincipal claimsPrincipal, string purchaseId, string paymentMethodData) + { + var merchantAccount = await _DbContext.SystemSettingValues.FindAsync(SystemSettings.PaymentData.AdyenMerchantAccount).ConfigureAwait(false); + var apiKey = await _DbContext.SystemSettingValues.FindAsync(SystemSettings.PaymentData.AdyenApiKey).ConfigureAwait(false); + var purchase = await _DbContext.Purchases.Include(p => p.TicketPurchases).FirstOrDefaultAsync(p => p.Id == purchaseId).ConfigureAwait(false); + + if (string.IsNullOrEmpty(merchantAccount?.SerializedValue)) + { + // TODO Error + return null; + } + + if (string.IsNullOrEmpty(apiKey?.SerializedValue)) + { + // TODO Error + return null; + } + + if (purchase == null) + { + // TODO Error + return null; + } + + var currencyGroup = purchase.TicketPurchases.GroupBy(x => x.Currency); + if (currencyGroup.Count() > 1) + { + // TODO Error + return null; + } + + var paymentRequest = JsonConvert.DeserializeObject(paymentMethodData); + + if (paymentRequest == null) + { + // TODO Error + return null; + } + + paymentRequest.MerchantAccount = merchantAccount.SerializedValue; + paymentRequest.Reference = purchase.Id; + paymentRequest.ReturnUrl = "https://your-company.com/checkout?shopperOrder=12xy.."; + paymentRequest.Amount = new Amount(currencyGroup.First().Key.ToCurrencyDto().To3DigitIso(), purchase.Price); + paymentRequest.ShopperInteraction = PaymentRequest.ShopperInteractionEnum.Ecommerce; + + //var paymentRequest = new PaymentRequest + //{ + // PaymentMethod = System.Text.Json.JsonSerializer.Deserialize(paymentMethodData), + // MerchantAccount = merchantAccount.SerializedValue, + // Reference = purchase.Id, + // ReturnUrl = "https://your-company.com/checkout?shopperOrder=12xy..", // TODO Checkout Seite mit Polling/Events/... + // Amount = new Amount(currencyGroup.First().Key.ToCurrencyDto().To3DigitIso(), purchase.Price), + // //CountryCode = new RegionInfo(CultureInfo.CurrentUICulture.LCID).TwoLetterISORegionName, + //}; + + //Create the http client + var config = new Config + { + XApiKey = apiKey.SerializedValue, + Environment = Adyen.Model.Environment.Test + }; + var client = new Adyen.Client(config); + var checkout = new PaymentsService(client); + var paymentResult = await checkout.PaymentsAsync(paymentRequest).ConfigureAwait(false); + return paymentResult; + } + + #region Helpers + + private async Task CreatePurchaseAsync(CartDto cart, ClaimsPrincipal claimsPrincipal) + { + var userId = claimsPrincipal.Id(); + var user = await _UserManager.FindByIdAsync(userId); + + if (user == null) + { + const string errorMessage = "User not found."; + _Logger.LogError(errorMessage); + return null; + } + + string purchaseId; + do + { + purchaseId = Guid.NewGuid().ToString(); + } + while ((await _DbContext.Purchases.FindAsync(purchaseId)) != null); + + var purchase = new Purchase + { + Id = purchaseId, + PurchaseTime = DateTime.UtcNow, + User = user, + UserId = user.Id, + }; + + await CreateTicketPurchasesAsync(cart, purchase).ConfigureAwait(false); + + return purchase; + } + + private async Task CreateTicketPurchasesAsync(CartDto cart, Purchase purchase) + { + var maxTicketPurchaseId = await _DbContext.TicketPurchases.MaxAsync(x => x.Id).ConfigureAwait(false); + var ticketPurchases = new List(); + foreach (var cartTicket in cart.CartEntries.Where(e => e.TicketId != null)) + { + var ticketType = await _DbContext.Tickets.FindAsync(cartTicket.TicketId).ConfigureAwait(false) ?? throw new NotSupportedException($"TicketId {cartTicket.TicketId} not found!"); + ticketPurchases.AddRange(Enumerable.Repeat(null, cartTicket.Amount).Select(_ => new TicketPurchase + { + Id = ++maxTicketPurchaseId, + Currency = ticketType.Currency, + Price = ticketType.Price, + Purchase = purchase, + PurchaseId = purchase.Id, + Ticket = ticketType, + TicketId = ticketType.Id + })); + } + + if (ticketPurchases.Any()) + { + purchase.TicketPurchases = ticketPurchases; + } + } + + #endregion + } +} diff --git a/NetEvent/Server/Helpers/DtoMapper.cs b/NetEvent/Server/Helpers/DtoMapper.cs index 922aa24f..13c3a126 100644 --- a/NetEvent/Server/Helpers/DtoMapper.cs +++ b/NetEvent/Server/Helpers/DtoMapper.cs @@ -1,4 +1,5 @@ using System.Security.Claims; +using Adyen.Model.Checkout; using NetEvent.Server.Models; using NetEvent.Shared.Dto; using NetEvent.Shared.Dto.Administration; @@ -18,10 +19,10 @@ public static partial class DtoMapper public static partial CurrentUserDto ToCurrentUserDto(this ApplicationUser applicationUser); - [MapProperty($"{nameof(ClaimsPrincipal.Identity)}.{nameof(ClaimsPrincipal.Identity.IsAuthenticated)}", nameof(CurrentUserDto.IsAuthenticated))] - [MapProperty($"{nameof(ClaimsPrincipal.Identity)}.{nameof(ClaimsPrincipal.Identity.Name)}", nameof(CurrentUserDto.UserName))] - [MapperIgnoreTarget(nameof(CurrentUserDto.Claims))] - public static partial CurrentUserDto ToCurrentUserDto(this ClaimsPrincipal claimsPrincipal); + //[MapProperty($"{nameof(ClaimsPrincipal.Identity)}.{nameof(ClaimsPrincipal.Identity.IsAuthenticated)}", nameof(CurrentUserDto.IsAuthenticated))] + //[MapProperty($"{nameof(ClaimsPrincipal.Identity)}.{nameof(ClaimsPrincipal.Identity.Name)}", nameof(CurrentUserDto.UserName))] + //[MapperIgnoreTarget(nameof(CurrentUserDto.Claims))] + //public static partial CurrentUserDto ToCurrentUserDto(this ClaimsPrincipal claimsPrincipal); [MapperIgnoreTarget(nameof(RoleDto.Claims))] public static partial RoleDto ToRoleDto(this ApplicationRole applicationRole); @@ -53,8 +54,20 @@ public static partial class DtoMapper public static partial Event ToEvent(this EventDto eventToConvert); + public static partial EventTicketTypeDto ToEventTicketTypeDto(this EventTicketType eventTicketTypeToConvert); + + public static partial EventTicketType ToEventTicketType(this EventTicketTypeDto eventTicketTypeToConvert); + + public static partial CurrencyDto ToCurrencyDto(this Currency currency); + public static partial VenueDto ToVenueDto(this Venue venue); public static partial Venue ToVenue(this VenueDto venue); + + public static partial CheckoutSessionDto ToCheckoutSessionDto(this CreateCheckoutSessionResponse createCheckoutSessionResponse); + + public static partial PaymentMethodDto ToPaymentMethodDto(this PaymentMethod paymentMethods); + + public static partial PurchaseDto ToPurchaseDto(this Purchase purchase); } } diff --git a/NetEvent/Server/Migrations/Psql/20230110210613_AddEventTicketType.Designer.cs b/NetEvent/Server/Migrations/Psql/20230110210613_AddEventTicketType.Designer.cs new file mode 100644 index 00000000..15a7fa44 --- /dev/null +++ b/NetEvent/Server/Migrations/Psql/20230110210613_AddEventTicketType.Designer.cs @@ -0,0 +1,740 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetEvent.Server.Data; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace NetEvent.Server.Migrations.Psql +{ + [DbContext(typeof(PsqlApplicationDbContext))] + [Migration("20230110210613_AddEventTicketType")] + partial class AddEventTicketType + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", (string)null); + + b.HasData( + new + { + Id = 1, + ClaimType = "Admin.Users.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 2, + ClaimType = "Admin.Users.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 3, + ClaimType = "Admin.Roles.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 4, + ClaimType = "Admin.Roles.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 5, + ClaimType = "Admin.System.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 6, + ClaimType = "Admin.System.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 7, + ClaimType = "Admin.Images.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 8, + ClaimType = "Admin.Images.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 9, + ClaimType = "Admin.Events.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 10, + ClaimType = "Admin.Events.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 11, + ClaimType = "Admin.Venues.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 12, + ClaimType = "Admin.Venues.Write", + ClaimValue = "", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", (string)null); + + b.HasData( + new + { + UserId = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("IsDefault") + .HasColumnType("boolean"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "user", + IsDefault = true, + Name = "User", + NormalizedName = "USER" + }, + new + { + Id = "orga", + IsDefault = false, + Name = "Orga", + NormalizedName = "ORGA" + }, + new + { + Id = "admin", + IsDefault = false, + Name = "Admin", + NormalizedName = "ADMIN" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("ProfilePicture") + .HasColumnType("bytea"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("User", (string)null); + + b.HasData( + new + { + Id = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + AccessFailedCount = 0, + ConcurrencyStamp = "f04ce91e-9530-4345-8cb6-ca7064b18f9e", + Email = "admin@admin.de", + EmailConfirmed = true, + FirstName = "Admin", + LastName = "istrator", + LockoutEnabled = false, + NormalizedEmail = "ADMIN@ADMIN.DE", + NormalizedUserName = "ADMIN", + PasswordHash = "AQAAAAIAAYagAAAAEBQZqmlKIsoqJXLPAEONrg4qS/LiDqczL05LikcpplHSrajOE+VxOsnzvK2Xq5bxig==", + PhoneNumberConfirmed = false, + SecurityStamp = "9529d94c-3a1d-4616-b977-af03e35856e8", + TwoFactorEnabled = false, + UserName = "admin" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EmailTemplate", b => + { + b.Property("TemplateId") + .HasColumnType("text"); + + b.Property("ContentTemplate") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubjectTemplate") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("TemplateId"); + + b.ToTable("EmailTemplates", (string)null); + + b.HasData( + new + { + TemplateId = "UserEmailConfirmEmailTemplate", + ContentTemplate = "

@Model.TemplateVariables[\"firstName\"], welcome to NetEvent.

\n

Please confirm your E-Mail by clicking on the following link:

@Model.TemplateVariables[\"confirmUrl\"] ", + SubjectTemplate = "@Model.TemplateVariables[\"firstName\"], please confirm your E-Mail address." + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("EventFormat") + .HasColumnType("integer"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ShortDescription") + .HasColumnType("text"); + + b.Property("Slug") + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("VenueId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Slug") + .IsUnique(); + + b.HasIndex("VenueId"); + + b.ToTable("Events", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AvailableTickets") + .HasColumnType("bigint"); + + b.Property("Currency") + .HasColumnType("integer"); + + b.Property("EventId") + .HasColumnType("bigint"); + + b.Property("IsGiftable") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("integer"); + + b.Property("SellEndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SellStartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Slug") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.ToTable("EventTicketTypes", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemImage", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("bytea"); + + b.Property("Extension") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("UploadTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("SystemImages", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemSettingValue", b => + { + b.Property("Key") + .HasColumnType("text"); + + b.Property("SerializedValue") + .HasColumnType("text"); + + b.HasKey("Key"); + + b.ToTable("SystemSettings", (string)null); + + b.HasData( + new + { + Key = "OrganizationName", + SerializedValue = "NetEvent" + }, + new + { + Key = "HideOrganizationNameInNavBar", + SerializedValue = "False" + }, + new + { + Key = "DataCultureInfo", + SerializedValue = "en-US" + }, + new + { + Key = "Favicon", + SerializedValue = "" + }, + new + { + Key = "Logo", + SerializedValue = "" + }, + new + { + Key = "AboutUs", + SerializedValue = "" + }, + new + { + Key = "LegalNotice", + SerializedValue = "" + }, + new + { + Key = "PrivacyPolicy", + SerializedValue = "" + }, + new + { + Key = "PrimaryColor", + SerializedValue = "" + }, + new + { + Key = "PrimaryTextColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryTextColor", + SerializedValue = "" + }, + new + { + Key = "Background", + SerializedValue = "" + }, + new + { + Key = "AppbarBackground", + SerializedValue = "" + }, + new + { + Key = "AppbarText", + SerializedValue = "" + }, + new + { + Key = "CustomCss", + SerializedValue = "" + }, + new + { + Key = "Standard", + SerializedValue = "True" + }, + new + { + Key = "Steam", + SerializedValue = "False" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Venue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("text"); + + b.Property("Slug") + .HasColumnType("text"); + + b.Property("Street") + .HasColumnType("text"); + + b.Property("ZipCode") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Venues", (string)null); + }); + + modelBuilder.Entity("NetEvent.Shared.Dto.ThemeDto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ThemeData") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Themes", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.HasOne("NetEvent.Server.Models.Venue", "Venue") + .WithMany() + .HasForeignKey("VenueId"); + + b.Navigation("Venue"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.HasOne("NetEvent.Server.Models.Event", "Event") + .WithMany("TicketTypes") + .HasForeignKey("EventId"); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Navigation("TicketTypes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/NetEvent/Server/Migrations/Psql/20230110210613_AddEventTicketType.cs b/NetEvent/Server/Migrations/Psql/20230110210613_AddEventTicketType.cs new file mode 100644 index 00000000..a62d414e --- /dev/null +++ b/NetEvent/Server/Migrations/Psql/20230110210613_AddEventTicketType.cs @@ -0,0 +1,120 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace NetEvent.Server.Migrations.Psql +{ + /// + public partial class AddEventTicketType : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "eventFormat", + table: "Events", + newName: "EventFormat"); + + migrationBuilder.CreateTable( + name: "EventTicketTypes", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: true), + Slug = table.Column(type: "text", nullable: true), + Price = table.Column(type: "integer", nullable: false), + Currency = table.Column(type: "integer", nullable: false), + AvailableTickets = table.Column(type: "bigint", nullable: false), + SellStartDate = table.Column(type: "timestamp with time zone", nullable: false), + SellEndDate = table.Column(type: "timestamp with time zone", nullable: false), + IsGiftable = table.Column(type: "boolean", nullable: false), + EventId = table.Column(type: "bigint", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_EventTicketTypes", x => x.Id); + table.ForeignKey( + name: "FK_EventTicketTypes_Events_EventId", + column: x => x.EventId, + principalTable: "Events", + principalColumn: "Id"); + }); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 8, + column: "ClaimType", + value: "Admin.Images.Write"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 10, + column: "ClaimType", + value: "Admin.Events.Write"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 12, + column: "ClaimType", + value: "Admin.Venues.Write"); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "f04ce91e-9530-4345-8cb6-ca7064b18f9e", "AQAAAAIAAYagAAAAEBQZqmlKIsoqJXLPAEONrg4qS/LiDqczL05LikcpplHSrajOE+VxOsnzvK2Xq5bxig==", "9529d94c-3a1d-4616-b977-af03e35856e8" }); + + migrationBuilder.CreateIndex( + name: "IX_EventTicketTypes_EventId", + table: "EventTicketTypes", + column: "EventId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "EventTicketTypes"); + + migrationBuilder.RenameColumn( + name: "EventFormat", + table: "Events", + newName: "eventFormat"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 8, + column: "ClaimType", + value: "Admin.Images.Edit"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 10, + column: "ClaimType", + value: "Admin.Events.Edit"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 12, + column: "ClaimType", + value: "Admin.Venues.Edit"); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "9b5238c9-c5a4-4790-8eb0-b78510682b41", "AQAAAAIAAYagAAAAEN5rDB2K6wk0FXO84PGiPx3h+VPc4QgpcSbFjQMFGAKW4SU+0nIM5Ee+5MXgDpZs1w==", "34e28843-865a-4bed-a77e-0d90d60b7547" }); + } + } +} diff --git a/NetEvent/Server/Migrations/Psql/20230126222513_AddTickets.Designer.cs b/NetEvent/Server/Migrations/Psql/20230126222513_AddTickets.Designer.cs new file mode 100644 index 00000000..4f8f9011 --- /dev/null +++ b/NetEvent/Server/Migrations/Psql/20230126222513_AddTickets.Designer.cs @@ -0,0 +1,834 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetEvent.Server.Data; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace NetEvent.Server.Migrations.Psql +{ + [DbContext(typeof(PsqlApplicationDbContext))] + [Migration("20230126222513_AddTickets")] + partial class AddTickets + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", (string)null); + + b.HasData( + new + { + Id = 1, + ClaimType = "Admin.Users.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 2, + ClaimType = "Admin.Users.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 3, + ClaimType = "Admin.Roles.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 4, + ClaimType = "Admin.Roles.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 5, + ClaimType = "Admin.System.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 6, + ClaimType = "Admin.System.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 7, + ClaimType = "Admin.Images.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 8, + ClaimType = "Admin.Images.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 9, + ClaimType = "Admin.Events.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 10, + ClaimType = "Admin.Events.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 11, + ClaimType = "Admin.Venues.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 12, + ClaimType = "Admin.Venues.Write", + ClaimValue = "", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", (string)null); + + b.HasData( + new + { + UserId = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("IsDefault") + .HasColumnType("boolean"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "user", + IsDefault = true, + Name = "User", + NormalizedName = "USER" + }, + new + { + Id = "orga", + IsDefault = false, + Name = "Orga", + NormalizedName = "ORGA" + }, + new + { + Id = "admin", + IsDefault = false, + Name = "Admin", + NormalizedName = "ADMIN" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("ProfilePicture") + .HasColumnType("bytea"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("User", (string)null); + + b.HasData( + new + { + Id = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + AccessFailedCount = 0, + ConcurrencyStamp = "eef6f288-f1da-41c2-81fa-95eae2e69410", + Email = "admin@admin.de", + EmailConfirmed = true, + FirstName = "Admin", + LastName = "istrator", + LockoutEnabled = false, + NormalizedEmail = "ADMIN@ADMIN.DE", + NormalizedUserName = "ADMIN", + PasswordHash = "AQAAAAIAAYagAAAAEK8gPOw/LRS1KOMtItdcM8BTgCAcUcbU/Vdonq1PDSC5X/SPhWNjh6eRCVI/eqRktw==", + PhoneNumberConfirmed = false, + SecurityStamp = "3806018a-661d-427c-8601-3ee04c4cc6a3", + TwoFactorEnabled = false, + UserName = "admin" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EmailTemplate", b => + { + b.Property("TemplateId") + .HasColumnType("text"); + + b.Property("ContentTemplate") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubjectTemplate") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("TemplateId"); + + b.ToTable("EmailTemplates", (string)null); + + b.HasData( + new + { + TemplateId = "UserEmailConfirmEmailTemplate", + ContentTemplate = "

@Model.TemplateVariables[\"firstName\"], welcome to NetEvent.

\n

Please confirm your E-Mail by clicking on the following link:

@Model.TemplateVariables[\"confirmUrl\"] ", + SubjectTemplate = "@Model.TemplateVariables[\"firstName\"], please confirm your E-Mail address." + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("EventFormat") + .HasColumnType("integer"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ShortDescription") + .HasColumnType("text"); + + b.Property("Slug") + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("VenueId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Slug") + .IsUnique(); + + b.HasIndex("VenueId"); + + b.ToTable("Events", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AvailableTickets") + .HasColumnType("bigint"); + + b.Property("Currency") + .HasColumnType("integer"); + + b.Property("EventId") + .HasColumnType("bigint"); + + b.Property("IsGiftable") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("integer"); + + b.Property("SellEndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SellStartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Slug") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.ToTable("EventTicketTypes", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("PurchaseTime") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Purchases", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemImage", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("bytea"); + + b.Property("Extension") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("UploadTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("SystemImages", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemSettingValue", b => + { + b.Property("Key") + .HasColumnType("text"); + + b.Property("SerializedValue") + .HasColumnType("text"); + + b.HasKey("Key"); + + b.ToTable("SystemSettings", (string)null); + + b.HasData( + new + { + Key = "OrganizationName", + SerializedValue = "NetEvent" + }, + new + { + Key = "HideOrganizationNameInNavBar", + SerializedValue = "False" + }, + new + { + Key = "DataCultureInfo", + SerializedValue = "en-US" + }, + new + { + Key = "Favicon", + SerializedValue = "" + }, + new + { + Key = "Logo", + SerializedValue = "" + }, + new + { + Key = "AboutUs", + SerializedValue = "" + }, + new + { + Key = "LegalNotice", + SerializedValue = "" + }, + new + { + Key = "PrivacyPolicy", + SerializedValue = "" + }, + new + { + Key = "PrimaryColor", + SerializedValue = "" + }, + new + { + Key = "PrimaryTextColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryTextColor", + SerializedValue = "" + }, + new + { + Key = "Background", + SerializedValue = "" + }, + new + { + Key = "AppbarBackground", + SerializedValue = "" + }, + new + { + Key = "AppbarText", + SerializedValue = "" + }, + new + { + Key = "CustomCss", + SerializedValue = "" + }, + new + { + Key = "Standard", + SerializedValue = "True" + }, + new + { + Key = "Steam", + SerializedValue = "False" + }, + new + { + Key = "AdyenApiKey", + SerializedValue = "" + }, + new + { + Key = "AdyenClientKey", + SerializedValue = "" + }, + new + { + Key = "AdyenMerchantAccount", + SerializedValue = "" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Currency") + .HasColumnType("integer"); + + b.Property("Price") + .HasColumnType("integer"); + + b.Property("PurchaseId") + .HasColumnType("bigint"); + + b.Property("TicketId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("PurchaseId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketPurchases", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Venue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("text"); + + b.Property("Slug") + .HasColumnType("text"); + + b.Property("Street") + .HasColumnType("text"); + + b.Property("ZipCode") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Venues", (string)null); + }); + + modelBuilder.Entity("NetEvent.Shared.Dto.ThemeDto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ThemeData") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Themes", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.HasOne("NetEvent.Server.Models.Venue", "Venue") + .WithMany() + .HasForeignKey("VenueId"); + + b.Navigation("Venue"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.HasOne("NetEvent.Server.Models.Event", "Event") + .WithMany("TicketTypes") + .HasForeignKey("EventId"); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.HasOne("NetEvent.Server.Models.Purchase", "Purchase") + .WithMany("TicketPurchases") + .HasForeignKey("PurchaseId"); + + b.HasOne("NetEvent.Server.Models.EventTicketType", "Ticket") + .WithMany() + .HasForeignKey("TicketId"); + + b.Navigation("Purchase"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Navigation("TicketTypes"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Navigation("TicketPurchases"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/NetEvent/Server/Migrations/Psql/20230126222513_AddTickets.cs b/NetEvent/Server/Migrations/Psql/20230126222513_AddTickets.cs new file mode 100644 index 00000000..d5adc746 --- /dev/null +++ b/NetEvent/Server/Migrations/Psql/20230126222513_AddTickets.cs @@ -0,0 +1,127 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace NetEvent.Server.Migrations.Psql +{ + /// + public partial class AddTickets : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Purchases", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + PurchaseTime = table.Column(type: "timestamp with time zone", nullable: true), + UserId = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Purchases", x => x.Id); + table.ForeignKey( + name: "FK_Purchases_User_UserId", + column: x => x.UserId, + principalTable: "User", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "TicketPurchases", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + TicketId = table.Column(type: "bigint", nullable: true), + PurchaseId = table.Column(type: "bigint", nullable: true), + Price = table.Column(type: "integer", nullable: false), + Currency = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TicketPurchases", x => x.Id); + table.ForeignKey( + name: "FK_TicketPurchases_EventTicketTypes_TicketId", + column: x => x.TicketId, + principalTable: "EventTicketTypes", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_TicketPurchases_Purchases_PurchaseId", + column: x => x.PurchaseId, + principalTable: "Purchases", + principalColumn: "Id"); + }); + + migrationBuilder.InsertData( + table: "SystemSettings", + columns: new[] { "Key", "SerializedValue" }, + values: new object[,] + { + { "AdyenApiKey", "" }, + { "AdyenClientKey", "" }, + { "AdyenMerchantAccount", "" } + }); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "eef6f288-f1da-41c2-81fa-95eae2e69410", "AQAAAAIAAYagAAAAEK8gPOw/LRS1KOMtItdcM8BTgCAcUcbU/Vdonq1PDSC5X/SPhWNjh6eRCVI/eqRktw==", "3806018a-661d-427c-8601-3ee04c4cc6a3" }); + + migrationBuilder.CreateIndex( + name: "IX_Purchases_UserId", + table: "Purchases", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_TicketPurchases_PurchaseId", + table: "TicketPurchases", + column: "PurchaseId"); + + migrationBuilder.CreateIndex( + name: "IX_TicketPurchases_TicketId", + table: "TicketPurchases", + column: "TicketId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "TicketPurchases"); + + migrationBuilder.DropTable( + name: "Purchases"); + + migrationBuilder.DeleteData( + table: "SystemSettings", + keyColumn: "Key", + keyValue: "AdyenApiKey"); + + migrationBuilder.DeleteData( + table: "SystemSettings", + keyColumn: "Key", + keyValue: "AdyenClientKey"); + + migrationBuilder.DeleteData( + table: "SystemSettings", + keyColumn: "Key", + keyValue: "AdyenMerchantAccount"); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "f04ce91e-9530-4345-8cb6-ca7064b18f9e", "AQAAAAIAAYagAAAAEBQZqmlKIsoqJXLPAEONrg4qS/LiDqczL05LikcpplHSrajOE+VxOsnzvK2Xq5bxig==", "9529d94c-3a1d-4616-b977-af03e35856e8" }); + } + } +} diff --git a/NetEvent/Server/Migrations/Psql/20230216225406_ChangePurchaseIdType.Designer.cs b/NetEvent/Server/Migrations/Psql/20230216225406_ChangePurchaseIdType.Designer.cs new file mode 100644 index 00000000..e5268ee2 --- /dev/null +++ b/NetEvent/Server/Migrations/Psql/20230216225406_ChangePurchaseIdType.Designer.cs @@ -0,0 +1,831 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetEvent.Server.Data; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace NetEvent.Server.Migrations.Psql +{ + [DbContext(typeof(PsqlApplicationDbContext))] + [Migration("20230216225406_ChangePurchaseIdType")] + partial class ChangePurchaseIdType + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", (string)null); + + b.HasData( + new + { + Id = 1, + ClaimType = "Admin.Users.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 2, + ClaimType = "Admin.Users.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 3, + ClaimType = "Admin.Roles.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 4, + ClaimType = "Admin.Roles.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 5, + ClaimType = "Admin.System.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 6, + ClaimType = "Admin.System.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 7, + ClaimType = "Admin.Images.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 8, + ClaimType = "Admin.Images.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 9, + ClaimType = "Admin.Events.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 10, + ClaimType = "Admin.Events.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 11, + ClaimType = "Admin.Venues.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 12, + ClaimType = "Admin.Venues.Write", + ClaimValue = "", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", (string)null); + + b.HasData( + new + { + UserId = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("IsDefault") + .HasColumnType("boolean"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "user", + IsDefault = true, + Name = "User", + NormalizedName = "USER" + }, + new + { + Id = "orga", + IsDefault = false, + Name = "Orga", + NormalizedName = "ORGA" + }, + new + { + Id = "admin", + IsDefault = false, + Name = "Admin", + NormalizedName = "ADMIN" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("ProfilePicture") + .HasColumnType("bytea"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("User", (string)null); + + b.HasData( + new + { + Id = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + AccessFailedCount = 0, + ConcurrencyStamp = "b379aa23-f095-4145-baba-e76f442552c0", + Email = "admin@admin.de", + EmailConfirmed = true, + FirstName = "Admin", + LastName = "istrator", + LockoutEnabled = false, + NormalizedEmail = "ADMIN@ADMIN.DE", + NormalizedUserName = "ADMIN", + PasswordHash = "AQAAAAIAAYagAAAAELfWRDoThz05sToVRCMx7OHbxw1L91Pm2RW5UN3xXun3e2YpIX0NJ1s8fmgFZnB+Eg==", + PhoneNumberConfirmed = false, + SecurityStamp = "0c5c2bf4-2389-49dd-bbe2-8c7b3962ef2b", + TwoFactorEnabled = false, + UserName = "admin" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EmailTemplate", b => + { + b.Property("TemplateId") + .HasColumnType("text"); + + b.Property("ContentTemplate") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubjectTemplate") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("TemplateId"); + + b.ToTable("EmailTemplates", (string)null); + + b.HasData( + new + { + TemplateId = "UserEmailConfirmEmailTemplate", + ContentTemplate = "

@Model.TemplateVariables[\"firstName\"], welcome to NetEvent.

\n

Please confirm your E-Mail by clicking on the following link:

@Model.TemplateVariables[\"confirmUrl\"] ", + SubjectTemplate = "@Model.TemplateVariables[\"firstName\"], please confirm your E-Mail address." + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("EventFormat") + .HasColumnType("integer"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ShortDescription") + .HasColumnType("text"); + + b.Property("Slug") + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("VenueId") + .HasColumnType("bigint"); + + b.Property("Visibility") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Slug") + .IsUnique(); + + b.HasIndex("VenueId"); + + b.ToTable("Events", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AvailableTickets") + .HasColumnType("bigint"); + + b.Property("Currency") + .HasColumnType("integer"); + + b.Property("EventId") + .HasColumnType("bigint"); + + b.Property("IsGiftable") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("integer"); + + b.Property("SellEndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SellStartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Slug") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.ToTable("EventTicketTypes", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("PurchaseTime") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Purchases", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemImage", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("bytea"); + + b.Property("Extension") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("UploadTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("SystemImages", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemSettingValue", b => + { + b.Property("Key") + .HasColumnType("text"); + + b.Property("SerializedValue") + .HasColumnType("text"); + + b.HasKey("Key"); + + b.ToTable("SystemSettings", (string)null); + + b.HasData( + new + { + Key = "OrganizationName", + SerializedValue = "NetEvent" + }, + new + { + Key = "HideOrganizationNameInNavBar", + SerializedValue = "False" + }, + new + { + Key = "DataCultureInfo", + SerializedValue = "en-US" + }, + new + { + Key = "Favicon", + SerializedValue = "" + }, + new + { + Key = "Logo", + SerializedValue = "" + }, + new + { + Key = "AboutUs", + SerializedValue = "" + }, + new + { + Key = "LegalNotice", + SerializedValue = "" + }, + new + { + Key = "PrivacyPolicy", + SerializedValue = "" + }, + new + { + Key = "PrimaryColor", + SerializedValue = "" + }, + new + { + Key = "PrimaryTextColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryTextColor", + SerializedValue = "" + }, + new + { + Key = "Background", + SerializedValue = "" + }, + new + { + Key = "AppbarBackground", + SerializedValue = "" + }, + new + { + Key = "AppbarText", + SerializedValue = "" + }, + new + { + Key = "CustomCss", + SerializedValue = "" + }, + new + { + Key = "Standard", + SerializedValue = "True" + }, + new + { + Key = "Steam", + SerializedValue = "False" + }, + new + { + Key = "AdyenApiKey", + SerializedValue = "" + }, + new + { + Key = "AdyenClientKey", + SerializedValue = "" + }, + new + { + Key = "AdyenMerchantAccount", + SerializedValue = "" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Currency") + .HasColumnType("integer"); + + b.Property("Price") + .HasColumnType("integer"); + + b.Property("PurchaseId") + .HasColumnType("text"); + + b.Property("TicketId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("PurchaseId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketPurchases", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Venue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("text"); + + b.Property("Slug") + .HasColumnType("text"); + + b.Property("Street") + .HasColumnType("text"); + + b.Property("ZipCode") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Venues", (string)null); + }); + + modelBuilder.Entity("NetEvent.Shared.Dto.ThemeDto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ThemeData") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Themes", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.HasOne("NetEvent.Server.Models.Venue", "Venue") + .WithMany() + .HasForeignKey("VenueId"); + + b.Navigation("Venue"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.HasOne("NetEvent.Server.Models.Event", "Event") + .WithMany("TicketTypes") + .HasForeignKey("EventId"); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.HasOne("NetEvent.Server.Models.Purchase", "Purchase") + .WithMany("TicketPurchases") + .HasForeignKey("PurchaseId"); + + b.HasOne("NetEvent.Server.Models.EventTicketType", "Ticket") + .WithMany() + .HasForeignKey("TicketId"); + + b.Navigation("Purchase"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Navigation("TicketTypes"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Navigation("TicketPurchases"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/NetEvent/Server/Migrations/Psql/20230216225406_ChangePurchaseIdType.cs b/NetEvent/Server/Migrations/Psql/20230216225406_ChangePurchaseIdType.cs new file mode 100644 index 00000000..dfd28096 --- /dev/null +++ b/NetEvent/Server/Migrations/Psql/20230216225406_ChangePurchaseIdType.cs @@ -0,0 +1,69 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace NetEvent.Server.Migrations.Psql +{ + /// + public partial class ChangePurchaseIdType : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "PurchaseId", + table: "TicketPurchases", + type: "text", + nullable: true, + oldClrType: typeof(long), + oldType: "bigint", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Purchases", + type: "text", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint") + .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "b379aa23-f095-4145-baba-e76f442552c0", "AQAAAAIAAYagAAAAELfWRDoThz05sToVRCMx7OHbxw1L91Pm2RW5UN3xXun3e2YpIX0NJ1s8fmgFZnB+Eg==", "0c5c2bf4-2389-49dd-bbe2-8c7b3962ef2b" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "PurchaseId", + table: "TicketPurchases", + type: "bigint", + nullable: true, + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Purchases", + type: "bigint", + nullable: false, + oldClrType: typeof(string), + oldType: "text") + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "eef6f288-f1da-41c2-81fa-95eae2e69410", "AQAAAAIAAYagAAAAEK8gPOw/LRS1KOMtItdcM8BTgCAcUcbU/Vdonq1PDSC5X/SPhWNjh6eRCVI/eqRktw==", "3806018a-661d-427c-8601-3ee04c4cc6a3" }); + } + } +} diff --git a/NetEvent/Server/Migrations/Psql/PsqlApplicationDbContextModelSnapshot.cs b/NetEvent/Server/Migrations/Psql/PsqlApplicationDbContextModelSnapshot.cs index 109ac7d9..044fae65 100644 --- a/NetEvent/Server/Migrations/Psql/PsqlApplicationDbContextModelSnapshot.cs +++ b/NetEvent/Server/Migrations/Psql/PsqlApplicationDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.2") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -99,7 +99,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { Id = 8, - ClaimType = "Admin.Images.Edit", + ClaimType = "Admin.Images.Write", ClaimValue = "", RoleId = "admin" }, @@ -113,7 +113,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { Id = 10, - ClaimType = "Admin.Events.Edit", + ClaimType = "Admin.Events.Write", ClaimValue = "", RoleId = "admin" }, @@ -127,7 +127,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { Id = 12, - ClaimType = "Admin.Venues.Edit", + ClaimType = "Admin.Venues.Write", ClaimValue = "", RoleId = "admin" }); @@ -354,7 +354,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { Id = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", AccessFailedCount = 0, - ConcurrencyStamp = "9b5238c9-c5a4-4790-8eb0-b78510682b41", + ConcurrencyStamp = "b379aa23-f095-4145-baba-e76f442552c0", Email = "admin@admin.de", EmailConfirmed = true, FirstName = "Admin", @@ -362,9 +362,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) LockoutEnabled = false, NormalizedEmail = "ADMIN@ADMIN.DE", NormalizedUserName = "ADMIN", - PasswordHash = "AQAAAAIAAYagAAAAEN5rDB2K6wk0FXO84PGiPx3h+VPc4QgpcSbFjQMFGAKW4SU+0nIM5Ee+5MXgDpZs1w==", + PasswordHash = "AQAAAAIAAYagAAAAELfWRDoThz05sToVRCMx7OHbxw1L91Pm2RW5UN3xXun3e2YpIX0NJ1s8fmgFZnB+Eg==", PhoneNumberConfirmed = false, - SecurityStamp = "34e28843-865a-4bed-a77e-0d90d60b7547", + SecurityStamp = "0c5c2bf4-2389-49dd-bbe2-8c7b3962ef2b", TwoFactorEnabled = false, UserName = "admin" }); @@ -410,6 +410,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("EndDate") .HasColumnType("timestamp with time zone"); + b.Property("EventFormat") + .HasColumnType("integer"); + b.Property("Name") .HasColumnType("text"); @@ -431,9 +434,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Visibility") .HasColumnType("integer"); - b.Property("eventFormat") - .HasColumnType("integer"); - b.HasKey("Id"); b.HasIndex("Slug") @@ -444,6 +444,66 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Events", (string)null); }); + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AvailableTickets") + .HasColumnType("bigint"); + + b.Property("Currency") + .HasColumnType("integer"); + + b.Property("EventId") + .HasColumnType("bigint"); + + b.Property("IsGiftable") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Price") + .HasColumnType("integer"); + + b.Property("SellEndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SellStartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Slug") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.ToTable("EventTicketTypes", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("PurchaseTime") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Purchases", (string)null); + }); + modelBuilder.Entity("NetEvent.Server.Models.SystemImage", b => { b.Property("Id") @@ -485,6 +545,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) SerializedValue = "NetEvent" }, new + { + Key = "HideOrganizationNameInNavBar", + SerializedValue = "False" + }, + new { Key = "DataCultureInfo", SerializedValue = "en-US" @@ -500,11 +565,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) SerializedValue = "" }, new - { - Key = "HideOrganizationNameInNavBar", - SerializedValue = "False" - }, - new { Key = "AboutUs", SerializedValue = "" @@ -568,9 +628,53 @@ protected override void BuildModel(ModelBuilder modelBuilder) { Key = "Steam", SerializedValue = "False" + }, + new + { + Key = "AdyenApiKey", + SerializedValue = "" + }, + new + { + Key = "AdyenClientKey", + SerializedValue = "" + }, + new + { + Key = "AdyenMerchantAccount", + SerializedValue = "" }); }); + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Currency") + .HasColumnType("integer"); + + b.Property("Price") + .HasColumnType("integer"); + + b.Property("PurchaseId") + .HasColumnType("text"); + + b.Property("TicketId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("PurchaseId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketPurchases", (string)null); + }); + modelBuilder.Entity("NetEvent.Server.Models.Venue", b => { b.Property("Id") @@ -675,6 +779,49 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Venue"); }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.HasOne("NetEvent.Server.Models.Event", "Event") + .WithMany("TicketTypes") + .HasForeignKey("EventId"); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.HasOne("NetEvent.Server.Models.Purchase", "Purchase") + .WithMany("TicketPurchases") + .HasForeignKey("PurchaseId"); + + b.HasOne("NetEvent.Server.Models.EventTicketType", "Ticket") + .WithMany() + .HasForeignKey("TicketId"); + + b.Navigation("Purchase"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Navigation("TicketTypes"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Navigation("TicketPurchases"); + }); #pragma warning restore 612, 618 } } diff --git a/NetEvent/Server/Migrations/Sqlite/20230110210600_AddEventTicketType.Designer.cs b/NetEvent/Server/Migrations/Sqlite/20230110210600_AddEventTicketType.Designer.cs new file mode 100644 index 00000000..fa880310 --- /dev/null +++ b/NetEvent/Server/Migrations/Sqlite/20230110210600_AddEventTicketType.Designer.cs @@ -0,0 +1,725 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetEvent.Server.Data; + +#nullable disable + +namespace NetEvent.Server.Migrations.Sqlite +{ + [DbContext(typeof(SqliteApplicationDbContext))] + [Migration("20230110210600_AddEventTicketType")] + partial class AddEventTicketType + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.1"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", (string)null); + + b.HasData( + new + { + Id = 1, + ClaimType = "Admin.Users.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 2, + ClaimType = "Admin.Users.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 3, + ClaimType = "Admin.Roles.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 4, + ClaimType = "Admin.Roles.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 5, + ClaimType = "Admin.System.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 6, + ClaimType = "Admin.System.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 7, + ClaimType = "Admin.Images.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 8, + ClaimType = "Admin.Images.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 9, + ClaimType = "Admin.Events.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 10, + ClaimType = "Admin.Events.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 11, + ClaimType = "Admin.Venues.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 12, + ClaimType = "Admin.Venues.Write", + ClaimValue = "", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", (string)null); + + b.HasData( + new + { + UserId = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "user", + IsDefault = true, + Name = "User", + NormalizedName = "USER" + }, + new + { + Id = "orga", + IsDefault = false, + Name = "Orga", + NormalizedName = "ORGA" + }, + new + { + Id = "admin", + IsDefault = false, + Name = "Admin", + NormalizedName = "ADMIN" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("FirstName") + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("ProfilePicture") + .HasColumnType("BLOB"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("User", (string)null); + + b.HasData( + new + { + Id = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + AccessFailedCount = 0, + ConcurrencyStamp = "26cbb106-629e-4b0f-b528-03e4fbaf148e", + Email = "admin@admin.de", + EmailConfirmed = true, + FirstName = "Admin", + LastName = "istrator", + LockoutEnabled = false, + NormalizedEmail = "ADMIN@ADMIN.DE", + NormalizedUserName = "ADMIN", + PasswordHash = "AQAAAAIAAYagAAAAEMVeCrEoGoqMFSa9mWv07gyORfXVq9Zash81NSc3Z4QmFWadfMKOABkphkaem7Q7nQ==", + PhoneNumberConfirmed = false, + SecurityStamp = "56b690d3-1bb2-4ef1-8fde-0397861a166b", + TwoFactorEnabled = false, + UserName = "admin" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EmailTemplate", b => + { + b.Property("TemplateId") + .HasColumnType("TEXT"); + + b.Property("ContentTemplate") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SubjectTemplate") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("TemplateId"); + + b.ToTable("EmailTemplates", (string)null); + + b.HasData( + new + { + TemplateId = "UserEmailConfirmEmailTemplate", + ContentTemplate = "

@Model.TemplateVariables[\"firstName\"], welcome to NetEvent.

\n

Please confirm your E-Mail by clicking on the following link:

@Model.TemplateVariables[\"confirmUrl\"] ", + SubjectTemplate = "@Model.TemplateVariables[\"firstName\"], please confirm your E-Mail address." + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EventFormat") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("ShortDescription") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.Property("VenueId") + .HasColumnType("INTEGER"); + + b.Property("Visibility") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Slug") + .IsUnique(); + + b.HasIndex("VenueId"); + + b.ToTable("Events", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AvailableTickets") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("EventId") + .HasColumnType("INTEGER"); + + b.Property("IsGiftable") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("SellEndDate") + .HasColumnType("TEXT"); + + b.Property("SellStartDate") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.ToTable("EventTicketTypes", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemImage", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("BLOB"); + + b.Property("Extension") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("UploadTime") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SystemImages", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemSettingValue", b => + { + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("SerializedValue") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("SystemSettings", (string)null); + + b.HasData( + new + { + Key = "OrganizationName", + SerializedValue = "NetEvent" + }, + new + { + Key = "HideOrganizationNameInNavBar", + SerializedValue = "False" + }, + new + { + Key = "DataCultureInfo", + SerializedValue = "en-US" + }, + new + { + Key = "Favicon", + SerializedValue = "" + }, + new + { + Key = "Logo", + SerializedValue = "" + }, + new + { + Key = "AboutUs", + SerializedValue = "" + }, + new + { + Key = "LegalNotice", + SerializedValue = "" + }, + new + { + Key = "PrivacyPolicy", + SerializedValue = "" + }, + new + { + Key = "PrimaryColor", + SerializedValue = "" + }, + new + { + Key = "PrimaryTextColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryTextColor", + SerializedValue = "" + }, + new + { + Key = "Background", + SerializedValue = "" + }, + new + { + Key = "AppbarBackground", + SerializedValue = "" + }, + new + { + Key = "AppbarText", + SerializedValue = "" + }, + new + { + Key = "CustomCss", + SerializedValue = "" + }, + new + { + Key = "Standard", + SerializedValue = "True" + }, + new + { + Key = "Steam", + SerializedValue = "False" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Venue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("City") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.Property("Street") + .HasColumnType("TEXT"); + + b.Property("ZipCode") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Venues", (string)null); + }); + + modelBuilder.Entity("NetEvent.Shared.Dto.ThemeDto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ThemeData") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Themes", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.HasOne("NetEvent.Server.Models.Venue", "Venue") + .WithMany() + .HasForeignKey("VenueId"); + + b.Navigation("Venue"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.HasOne("NetEvent.Server.Models.Event", "Event") + .WithMany("TicketTypes") + .HasForeignKey("EventId"); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Navigation("TicketTypes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/NetEvent/Server/Migrations/Sqlite/20230110210600_AddEventTicketType.cs b/NetEvent/Server/Migrations/Sqlite/20230110210600_AddEventTicketType.cs new file mode 100644 index 00000000..ca54c478 --- /dev/null +++ b/NetEvent/Server/Migrations/Sqlite/20230110210600_AddEventTicketType.cs @@ -0,0 +1,119 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace NetEvent.Server.Migrations.Sqlite +{ + /// + public partial class AddEventTicketType : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "eventFormat", + table: "Events", + newName: "EventFormat"); + + migrationBuilder.CreateTable( + name: "EventTicketTypes", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: true), + Slug = table.Column(type: "TEXT", nullable: true), + Price = table.Column(type: "INTEGER", nullable: false), + Currency = table.Column(type: "INTEGER", nullable: false), + AvailableTickets = table.Column(type: "INTEGER", nullable: false), + SellStartDate = table.Column(type: "TEXT", nullable: false), + SellEndDate = table.Column(type: "TEXT", nullable: false), + IsGiftable = table.Column(type: "INTEGER", nullable: false), + EventId = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_EventTicketTypes", x => x.Id); + table.ForeignKey( + name: "FK_EventTicketTypes_Events_EventId", + column: x => x.EventId, + principalTable: "Events", + principalColumn: "Id"); + }); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 8, + column: "ClaimType", + value: "Admin.Images.Write"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 10, + column: "ClaimType", + value: "Admin.Events.Write"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 12, + column: "ClaimType", + value: "Admin.Venues.Write"); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "26cbb106-629e-4b0f-b528-03e4fbaf148e", "AQAAAAIAAYagAAAAEMVeCrEoGoqMFSa9mWv07gyORfXVq9Zash81NSc3Z4QmFWadfMKOABkphkaem7Q7nQ==", "56b690d3-1bb2-4ef1-8fde-0397861a166b" }); + + migrationBuilder.CreateIndex( + name: "IX_EventTicketTypes_EventId", + table: "EventTicketTypes", + column: "EventId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "EventTicketTypes"); + + migrationBuilder.RenameColumn( + name: "EventFormat", + table: "Events", + newName: "eventFormat"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 8, + column: "ClaimType", + value: "Admin.Images.Edit"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 10, + column: "ClaimType", + value: "Admin.Events.Edit"); + + migrationBuilder.UpdateData( + table: "RoleClaims", + keyColumn: "Id", + keyValue: 12, + column: "ClaimType", + value: "Admin.Venues.Edit"); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "f205a4d6-cbab-4163-9427-32802498bc59", "AQAAAAIAAYagAAAAEF+OwzkcGgbWzhEmVd7Xy0iRHQU842tguftE2WfkQvSDLy8ZHNXzDqg57vVgrCdioA==", "a9023bf7-6259-40e8-a944-8aae466e9709" }); + } + } +} diff --git a/NetEvent/Server/Migrations/Sqlite/20230126222503_AddTickets.Designer.cs b/NetEvent/Server/Migrations/Sqlite/20230126222503_AddTickets.Designer.cs new file mode 100644 index 00000000..8e2eaae4 --- /dev/null +++ b/NetEvent/Server/Migrations/Sqlite/20230126222503_AddTickets.Designer.cs @@ -0,0 +1,815 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetEvent.Server.Data; + +#nullable disable + +namespace NetEvent.Server.Migrations.Sqlite +{ + [DbContext(typeof(SqliteApplicationDbContext))] + [Migration("20230126222503_AddTickets")] + partial class AddTickets + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.2"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", (string)null); + + b.HasData( + new + { + Id = 1, + ClaimType = "Admin.Users.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 2, + ClaimType = "Admin.Users.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 3, + ClaimType = "Admin.Roles.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 4, + ClaimType = "Admin.Roles.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 5, + ClaimType = "Admin.System.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 6, + ClaimType = "Admin.System.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 7, + ClaimType = "Admin.Images.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 8, + ClaimType = "Admin.Images.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 9, + ClaimType = "Admin.Events.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 10, + ClaimType = "Admin.Events.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 11, + ClaimType = "Admin.Venues.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 12, + ClaimType = "Admin.Venues.Write", + ClaimValue = "", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", (string)null); + + b.HasData( + new + { + UserId = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "user", + IsDefault = true, + Name = "User", + NormalizedName = "USER" + }, + new + { + Id = "orga", + IsDefault = false, + Name = "Orga", + NormalizedName = "ORGA" + }, + new + { + Id = "admin", + IsDefault = false, + Name = "Admin", + NormalizedName = "ADMIN" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("FirstName") + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("ProfilePicture") + .HasColumnType("BLOB"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("User", (string)null); + + b.HasData( + new + { + Id = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + AccessFailedCount = 0, + ConcurrencyStamp = "5d10c057-f0c5-4439-9ea5-52da9de25db4", + Email = "admin@admin.de", + EmailConfirmed = true, + FirstName = "Admin", + LastName = "istrator", + LockoutEnabled = false, + NormalizedEmail = "ADMIN@ADMIN.DE", + NormalizedUserName = "ADMIN", + PasswordHash = "AQAAAAIAAYagAAAAEHl8xBgwOlrJfSfDpoRyQLa1TdrX7zMysaC62jvZEjAyngzzdjD+zyfPkY2zk66ZGQ==", + PhoneNumberConfirmed = false, + SecurityStamp = "83f864b3-fb09-44e4-9e5c-748beadc4af3", + TwoFactorEnabled = false, + UserName = "admin" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EmailTemplate", b => + { + b.Property("TemplateId") + .HasColumnType("TEXT"); + + b.Property("ContentTemplate") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SubjectTemplate") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("TemplateId"); + + b.ToTable("EmailTemplates", (string)null); + + b.HasData( + new + { + TemplateId = "UserEmailConfirmEmailTemplate", + ContentTemplate = "

@Model.TemplateVariables[\"firstName\"], welcome to NetEvent.

\n

Please confirm your E-Mail by clicking on the following link:

@Model.TemplateVariables[\"confirmUrl\"] ", + SubjectTemplate = "@Model.TemplateVariables[\"firstName\"], please confirm your E-Mail address." + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EventFormat") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("ShortDescription") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.Property("VenueId") + .HasColumnType("INTEGER"); + + b.Property("Visibility") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Slug") + .IsUnique(); + + b.HasIndex("VenueId"); + + b.ToTable("Events", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AvailableTickets") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("EventId") + .HasColumnType("INTEGER"); + + b.Property("IsGiftable") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("SellEndDate") + .HasColumnType("TEXT"); + + b.Property("SellStartDate") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.ToTable("EventTicketTypes", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("PurchaseTime") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Purchases", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemImage", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("BLOB"); + + b.Property("Extension") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("UploadTime") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SystemImages", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemSettingValue", b => + { + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("SerializedValue") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("SystemSettings", (string)null); + + b.HasData( + new + { + Key = "OrganizationName", + SerializedValue = "NetEvent" + }, + new + { + Key = "HideOrganizationNameInNavBar", + SerializedValue = "False" + }, + new + { + Key = "DataCultureInfo", + SerializedValue = "en-US" + }, + new + { + Key = "Favicon", + SerializedValue = "" + }, + new + { + Key = "Logo", + SerializedValue = "" + }, + new + { + Key = "AboutUs", + SerializedValue = "" + }, + new + { + Key = "LegalNotice", + SerializedValue = "" + }, + new + { + Key = "PrivacyPolicy", + SerializedValue = "" + }, + new + { + Key = "PrimaryColor", + SerializedValue = "" + }, + new + { + Key = "PrimaryTextColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryTextColor", + SerializedValue = "" + }, + new + { + Key = "Background", + SerializedValue = "" + }, + new + { + Key = "AppbarBackground", + SerializedValue = "" + }, + new + { + Key = "AppbarText", + SerializedValue = "" + }, + new + { + Key = "CustomCss", + SerializedValue = "" + }, + new + { + Key = "Standard", + SerializedValue = "True" + }, + new + { + Key = "Steam", + SerializedValue = "False" + }, + new + { + Key = "AdyenApiKey", + SerializedValue = "" + }, + new + { + Key = "AdyenClientKey", + SerializedValue = "" + }, + new + { + Key = "AdyenMerchantAccount", + SerializedValue = "" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("PurchaseId") + .HasColumnType("INTEGER"); + + b.Property("TicketId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PurchaseId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketPurchases", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Venue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("City") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.Property("Street") + .HasColumnType("TEXT"); + + b.Property("ZipCode") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Venues", (string)null); + }); + + modelBuilder.Entity("NetEvent.Shared.Dto.ThemeDto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ThemeData") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Themes", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.HasOne("NetEvent.Server.Models.Venue", "Venue") + .WithMany() + .HasForeignKey("VenueId"); + + b.Navigation("Venue"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.HasOne("NetEvent.Server.Models.Event", "Event") + .WithMany("TicketTypes") + .HasForeignKey("EventId"); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.HasOne("NetEvent.Server.Models.Purchase", "Purchase") + .WithMany("TicketPurchases") + .HasForeignKey("PurchaseId"); + + b.HasOne("NetEvent.Server.Models.EventTicketType", "Ticket") + .WithMany() + .HasForeignKey("TicketId"); + + b.Navigation("Purchase"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Navigation("TicketTypes"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Navigation("TicketPurchases"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/NetEvent/Server/Migrations/Sqlite/20230126222503_AddTickets.cs b/NetEvent/Server/Migrations/Sqlite/20230126222503_AddTickets.cs new file mode 100644 index 00000000..865047ba --- /dev/null +++ b/NetEvent/Server/Migrations/Sqlite/20230126222503_AddTickets.cs @@ -0,0 +1,126 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace NetEvent.Server.Migrations.Sqlite +{ + /// + public partial class AddTickets : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Purchases", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + PurchaseTime = table.Column(type: "TEXT", nullable: true), + UserId = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Purchases", x => x.Id); + table.ForeignKey( + name: "FK_Purchases_User_UserId", + column: x => x.UserId, + principalTable: "User", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "TicketPurchases", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + TicketId = table.Column(type: "INTEGER", nullable: true), + PurchaseId = table.Column(type: "INTEGER", nullable: true), + Price = table.Column(type: "INTEGER", nullable: false), + Currency = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TicketPurchases", x => x.Id); + table.ForeignKey( + name: "FK_TicketPurchases_EventTicketTypes_TicketId", + column: x => x.TicketId, + principalTable: "EventTicketTypes", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_TicketPurchases_Purchases_PurchaseId", + column: x => x.PurchaseId, + principalTable: "Purchases", + principalColumn: "Id"); + }); + + migrationBuilder.InsertData( + table: "SystemSettings", + columns: new[] { "Key", "SerializedValue" }, + values: new object[,] + { + { "AdyenApiKey", "" }, + { "AdyenClientKey", "" }, + { "AdyenMerchantAccount", "" } + }); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "5d10c057-f0c5-4439-9ea5-52da9de25db4", "AQAAAAIAAYagAAAAEHl8xBgwOlrJfSfDpoRyQLa1TdrX7zMysaC62jvZEjAyngzzdjD+zyfPkY2zk66ZGQ==", "83f864b3-fb09-44e4-9e5c-748beadc4af3" }); + + migrationBuilder.CreateIndex( + name: "IX_Purchases_UserId", + table: "Purchases", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_TicketPurchases_PurchaseId", + table: "TicketPurchases", + column: "PurchaseId"); + + migrationBuilder.CreateIndex( + name: "IX_TicketPurchases_TicketId", + table: "TicketPurchases", + column: "TicketId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "TicketPurchases"); + + migrationBuilder.DropTable( + name: "Purchases"); + + migrationBuilder.DeleteData( + table: "SystemSettings", + keyColumn: "Key", + keyValue: "AdyenApiKey"); + + migrationBuilder.DeleteData( + table: "SystemSettings", + keyColumn: "Key", + keyValue: "AdyenClientKey"); + + migrationBuilder.DeleteData( + table: "SystemSettings", + keyColumn: "Key", + keyValue: "AdyenMerchantAccount"); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "26cbb106-629e-4b0f-b528-03e4fbaf148e", "AQAAAAIAAYagAAAAEMVeCrEoGoqMFSa9mWv07gyORfXVq9Zash81NSc3Z4QmFWadfMKOABkphkaem7Q7nQ==", "56b690d3-1bb2-4ef1-8fde-0397861a166b" }); + } + } +} diff --git a/NetEvent/Server/Migrations/Sqlite/20230216225358_ChangePurchaseIdType.Designer.cs b/NetEvent/Server/Migrations/Sqlite/20230216225358_ChangePurchaseIdType.Designer.cs new file mode 100644 index 00000000..e57f5788 --- /dev/null +++ b/NetEvent/Server/Migrations/Sqlite/20230216225358_ChangePurchaseIdType.Designer.cs @@ -0,0 +1,814 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetEvent.Server.Data; + +#nullable disable + +namespace NetEvent.Server.Migrations.Sqlite +{ + [DbContext(typeof(SqliteApplicationDbContext))] + [Migration("20230216225358_ChangePurchaseIdType")] + partial class ChangePurchaseIdType + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.2"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", (string)null); + + b.HasData( + new + { + Id = 1, + ClaimType = "Admin.Users.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 2, + ClaimType = "Admin.Users.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 3, + ClaimType = "Admin.Roles.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 4, + ClaimType = "Admin.Roles.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 5, + ClaimType = "Admin.System.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 6, + ClaimType = "Admin.System.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 7, + ClaimType = "Admin.Images.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 8, + ClaimType = "Admin.Images.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 9, + ClaimType = "Admin.Events.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 10, + ClaimType = "Admin.Events.Write", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 11, + ClaimType = "Admin.Venues.Read", + ClaimValue = "", + RoleId = "admin" + }, + new + { + Id = 12, + ClaimType = "Admin.Venues.Write", + ClaimValue = "", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", (string)null); + + b.HasData( + new + { + UserId = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + RoleId = "admin" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "user", + IsDefault = true, + Name = "User", + NormalizedName = "USER" + }, + new + { + Id = "orga", + IsDefault = false, + Name = "Orga", + NormalizedName = "ORGA" + }, + new + { + Id = "admin", + IsDefault = false, + Name = "Admin", + NormalizedName = "ADMIN" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("FirstName") + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("ProfilePicture") + .HasColumnType("BLOB"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("User", (string)null); + + b.HasData( + new + { + Id = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + AccessFailedCount = 0, + ConcurrencyStamp = "d07882b0-10fa-4ee6-8bf2-231f80fb4656", + Email = "admin@admin.de", + EmailConfirmed = true, + FirstName = "Admin", + LastName = "istrator", + LockoutEnabled = false, + NormalizedEmail = "ADMIN@ADMIN.DE", + NormalizedUserName = "ADMIN", + PasswordHash = "AQAAAAIAAYagAAAAEJoG+/hCI6v6EHNg+X2s0QzmdcRbSeNwg8rNju5+pXfaezhvxch9oAXvljZaNVeJbg==", + PhoneNumberConfirmed = false, + SecurityStamp = "dce345b2-0622-4092-9182-afc2c76cc50a", + TwoFactorEnabled = false, + UserName = "admin" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EmailTemplate", b => + { + b.Property("TemplateId") + .HasColumnType("TEXT"); + + b.Property("ContentTemplate") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SubjectTemplate") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("TemplateId"); + + b.ToTable("EmailTemplates", (string)null); + + b.HasData( + new + { + TemplateId = "UserEmailConfirmEmailTemplate", + ContentTemplate = "

@Model.TemplateVariables[\"firstName\"], welcome to NetEvent.

\n

Please confirm your E-Mail by clicking on the following link:

@Model.TemplateVariables[\"confirmUrl\"] ", + SubjectTemplate = "@Model.TemplateVariables[\"firstName\"], please confirm your E-Mail address." + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("EventFormat") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("ShortDescription") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.Property("VenueId") + .HasColumnType("INTEGER"); + + b.Property("Visibility") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Slug") + .IsUnique(); + + b.HasIndex("VenueId"); + + b.ToTable("Events", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AvailableTickets") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("EventId") + .HasColumnType("INTEGER"); + + b.Property("IsGiftable") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("SellEndDate") + .HasColumnType("TEXT"); + + b.Property("SellStartDate") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.ToTable("EventTicketTypes", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("PurchaseTime") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Purchases", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemImage", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("BLOB"); + + b.Property("Extension") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("UploadTime") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SystemImages", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.SystemSettingValue", b => + { + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("SerializedValue") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("SystemSettings", (string)null); + + b.HasData( + new + { + Key = "OrganizationName", + SerializedValue = "NetEvent" + }, + new + { + Key = "HideOrganizationNameInNavBar", + SerializedValue = "False" + }, + new + { + Key = "DataCultureInfo", + SerializedValue = "en-US" + }, + new + { + Key = "Favicon", + SerializedValue = "" + }, + new + { + Key = "Logo", + SerializedValue = "" + }, + new + { + Key = "AboutUs", + SerializedValue = "" + }, + new + { + Key = "LegalNotice", + SerializedValue = "" + }, + new + { + Key = "PrivacyPolicy", + SerializedValue = "" + }, + new + { + Key = "PrimaryColor", + SerializedValue = "" + }, + new + { + Key = "PrimaryTextColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryColor", + SerializedValue = "" + }, + new + { + Key = "SecondaryTextColor", + SerializedValue = "" + }, + new + { + Key = "Background", + SerializedValue = "" + }, + new + { + Key = "AppbarBackground", + SerializedValue = "" + }, + new + { + Key = "AppbarText", + SerializedValue = "" + }, + new + { + Key = "CustomCss", + SerializedValue = "" + }, + new + { + Key = "Standard", + SerializedValue = "True" + }, + new + { + Key = "Steam", + SerializedValue = "False" + }, + new + { + Key = "AdyenApiKey", + SerializedValue = "" + }, + new + { + Key = "AdyenClientKey", + SerializedValue = "" + }, + new + { + Key = "AdyenMerchantAccount", + SerializedValue = "" + }); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("PurchaseId") + .HasColumnType("TEXT"); + + b.Property("TicketId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PurchaseId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketPurchases", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Venue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("City") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.Property("Street") + .HasColumnType("TEXT"); + + b.Property("ZipCode") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Venues", (string)null); + }); + + modelBuilder.Entity("NetEvent.Shared.Dto.ThemeDto", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ThemeData") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Themes", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.HasOne("NetEvent.Server.Models.Venue", "Venue") + .WithMany() + .HasForeignKey("VenueId"); + + b.Navigation("Venue"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.HasOne("NetEvent.Server.Models.Event", "Event") + .WithMany("TicketTypes") + .HasForeignKey("EventId"); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.HasOne("NetEvent.Server.Models.Purchase", "Purchase") + .WithMany("TicketPurchases") + .HasForeignKey("PurchaseId"); + + b.HasOne("NetEvent.Server.Models.EventTicketType", "Ticket") + .WithMany() + .HasForeignKey("TicketId"); + + b.Navigation("Purchase"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Navigation("TicketTypes"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Navigation("TicketPurchases"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/NetEvent/Server/Migrations/Sqlite/20230216225358_ChangePurchaseIdType.cs b/NetEvent/Server/Migrations/Sqlite/20230216225358_ChangePurchaseIdType.cs new file mode 100644 index 00000000..88405b2d --- /dev/null +++ b/NetEvent/Server/Migrations/Sqlite/20230216225358_ChangePurchaseIdType.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace NetEvent.Server.Migrations.Sqlite +{ + /// + public partial class ChangePurchaseIdType : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "PurchaseId", + table: "TicketPurchases", + type: "TEXT", + nullable: true, + oldClrType: typeof(long), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Purchases", + type: "TEXT", + nullable: false, + oldClrType: typeof(long), + oldType: "INTEGER") + .OldAnnotation("Sqlite:Autoincrement", true); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "d07882b0-10fa-4ee6-8bf2-231f80fb4656", "AQAAAAIAAYagAAAAEJoG+/hCI6v6EHNg+X2s0QzmdcRbSeNwg8rNju5+pXfaezhvxch9oAXvljZaNVeJbg==", "dce345b2-0622-4092-9182-afc2c76cc50a" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "PurchaseId", + table: "TicketPurchases", + type: "INTEGER", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Id", + table: "Purchases", + type: "INTEGER", + nullable: false, + oldClrType: typeof(string), + oldType: "TEXT") + .Annotation("Sqlite:Autoincrement", true); + + migrationBuilder.UpdateData( + table: "User", + keyColumn: "Id", + keyValue: "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "5d10c057-f0c5-4439-9ea5-52da9de25db4", "AQAAAAIAAYagAAAAEHl8xBgwOlrJfSfDpoRyQLa1TdrX7zMysaC62jvZEjAyngzzdjD+zyfPkY2zk66ZGQ==", "83f864b3-fb09-44e4-9e5c-748beadc4af3" }); + } + } +} diff --git a/NetEvent/Server/Migrations/Sqlite/SqliteApplicationDbContextModelSnapshot.cs b/NetEvent/Server/Migrations/Sqlite/SqliteApplicationDbContextModelSnapshot.cs index ee970d15..78208921 100644 --- a/NetEvent/Server/Migrations/Sqlite/SqliteApplicationDbContextModelSnapshot.cs +++ b/NetEvent/Server/Migrations/Sqlite/SqliteApplicationDbContextModelSnapshot.cs @@ -15,7 +15,7 @@ partial class SqliteApplicationDbContextModelSnapshot : ModelSnapshot protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.0"); + modelBuilder.HasAnnotation("ProductVersion", "7.0.2"); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { @@ -92,7 +92,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { Id = 8, - ClaimType = "Admin.Images.Edit", + ClaimType = "Admin.Images.Write", ClaimValue = "", RoleId = "admin" }, @@ -106,7 +106,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { Id = 10, - ClaimType = "Admin.Events.Edit", + ClaimType = "Admin.Events.Write", ClaimValue = "", RoleId = "admin" }, @@ -120,7 +120,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { Id = 12, - ClaimType = "Admin.Venues.Edit", + ClaimType = "Admin.Venues.Write", ClaimValue = "", RoleId = "admin" }); @@ -345,7 +345,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { Id = "BAFC89CF-4F3E-4595-8256-CCA19C260FBD", AccessFailedCount = 0, - ConcurrencyStamp = "f205a4d6-cbab-4163-9427-32802498bc59", + ConcurrencyStamp = "d07882b0-10fa-4ee6-8bf2-231f80fb4656", Email = "admin@admin.de", EmailConfirmed = true, FirstName = "Admin", @@ -353,9 +353,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) LockoutEnabled = false, NormalizedEmail = "ADMIN@ADMIN.DE", NormalizedUserName = "ADMIN", - PasswordHash = "AQAAAAIAAYagAAAAEF+OwzkcGgbWzhEmVd7Xy0iRHQU842tguftE2WfkQvSDLy8ZHNXzDqg57vVgrCdioA==", + PasswordHash = "AQAAAAIAAYagAAAAEJoG+/hCI6v6EHNg+X2s0QzmdcRbSeNwg8rNju5+pXfaezhvxch9oAXvljZaNVeJbg==", PhoneNumberConfirmed = false, - SecurityStamp = "a9023bf7-6259-40e8-a944-8aae466e9709", + SecurityStamp = "dce345b2-0622-4092-9182-afc2c76cc50a", TwoFactorEnabled = false, UserName = "admin" }); @@ -399,6 +399,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("EndDate") .HasColumnType("TEXT"); + b.Property("EventFormat") + .HasColumnType("INTEGER"); + b.Property("Name") .HasColumnType("TEXT"); @@ -420,9 +423,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Visibility") .HasColumnType("INTEGER"); - b.Property("eventFormat") - .HasColumnType("INTEGER"); - b.HasKey("Id"); b.HasIndex("Slug") @@ -433,6 +433,64 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Events", (string)null); }); + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AvailableTickets") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("EventId") + .HasColumnType("INTEGER"); + + b.Property("IsGiftable") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("SellEndDate") + .HasColumnType("TEXT"); + + b.Property("SellStartDate") + .HasColumnType("TEXT"); + + b.Property("Slug") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.ToTable("EventTicketTypes", (string)null); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("PurchaseTime") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Purchases", (string)null); + }); + modelBuilder.Entity("NetEvent.Server.Models.SystemImage", b => { b.Property("Id") @@ -474,6 +532,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) SerializedValue = "NetEvent" }, new + { + Key = "HideOrganizationNameInNavBar", + SerializedValue = "False" + }, + new { Key = "DataCultureInfo", SerializedValue = "en-US" @@ -489,11 +552,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) SerializedValue = "" }, new - { - Key = "HideOrganizationNameInNavBar", - SerializedValue = "False" - }, - new { Key = "AboutUs", SerializedValue = "" @@ -557,9 +615,51 @@ protected override void BuildModel(ModelBuilder modelBuilder) { Key = "Steam", SerializedValue = "False" + }, + new + { + Key = "AdyenApiKey", + SerializedValue = "" + }, + new + { + Key = "AdyenClientKey", + SerializedValue = "" + }, + new + { + Key = "AdyenMerchantAccount", + SerializedValue = "" }); }); + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("PurchaseId") + .HasColumnType("TEXT"); + + b.Property("TicketId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PurchaseId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketPurchases", (string)null); + }); + modelBuilder.Entity("NetEvent.Server.Models.Venue", b => { b.Property("Id") @@ -662,6 +762,49 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Venue"); }); + + modelBuilder.Entity("NetEvent.Server.Models.EventTicketType", b => + { + b.HasOne("NetEvent.Server.Models.Event", "Event") + .WithMany("TicketTypes") + .HasForeignKey("EventId"); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.HasOne("NetEvent.Server.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.TicketPurchase", b => + { + b.HasOne("NetEvent.Server.Models.Purchase", "Purchase") + .WithMany("TicketPurchases") + .HasForeignKey("PurchaseId"); + + b.HasOne("NetEvent.Server.Models.EventTicketType", "Ticket") + .WithMany() + .HasForeignKey("TicketId"); + + b.Navigation("Purchase"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Event", b => + { + b.Navigation("TicketTypes"); + }); + + modelBuilder.Entity("NetEvent.Server.Models.Purchase", b => + { + b.Navigation("TicketPurchases"); + }); #pragma warning restore 612, 618 } } diff --git a/NetEvent/Server/Models/Currency.cs b/NetEvent/Server/Models/Currency.cs new file mode 100644 index 00000000..c233b128 --- /dev/null +++ b/NetEvent/Server/Models/Currency.cs @@ -0,0 +1,6 @@ +namespace NetEvent.Server.Models; + +public enum Currency +{ + Euro, +} diff --git a/NetEvent/Server/Models/Event.cs b/NetEvent/Server/Models/Event.cs index 7136c029..3683b72f 100644 --- a/NetEvent/Server/Models/Event.cs +++ b/NetEvent/Server/Models/Event.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Microsoft.EntityFrameworkCore; @@ -33,5 +34,8 @@ public class Event [ForeignKey(nameof(VenueId))] public Venue? Venue { get; set; } + + [InverseProperty(nameof(EventTicketType.Event))] + public IList? TicketTypes { get; set; } } } diff --git a/NetEvent/Server/Models/EventParticipant.cs b/NetEvent/Server/Models/EventParticipant.cs new file mode 100644 index 00000000..f9056f93 --- /dev/null +++ b/NetEvent/Server/Models/EventParticipant.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace NetEvent.Server.Models; + +public class EventParticipant +{ + [Key] + public long? Id { get; set; } + + public DateTime Created { get; set; } + + public long? TicketId { get; set; } + + [ForeignKey(nameof(TicketId))] + public EventTicket? Ticket { get; set; } +} diff --git a/NetEvent/Server/Models/EventTicket.cs b/NetEvent/Server/Models/EventTicket.cs new file mode 100644 index 00000000..1fb71d22 --- /dev/null +++ b/NetEvent/Server/Models/EventTicket.cs @@ -0,0 +1,25 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace NetEvent.Server.Models; + +public class EventTicket +{ + [Key] + public long? Id { get; set; } + + public long? UserId { get; set; } + + [ForeignKey(nameof(UserId))] + public ApplicationUser? User { get; set; } + + public long? TicketPurchaseId { get; set; } + + [ForeignKey(nameof(TicketPurchaseId))] + public TicketPurchase? TicketPurchase { get; set; } + + public long? GiftedTicketId { get; set; } + + [ForeignKey(nameof(GiftedTicketId))] + public EventTicket? GiftedTicket { get; set; } +} diff --git a/NetEvent/Server/Models/EventTicketType.cs b/NetEvent/Server/Models/EventTicketType.cs new file mode 100644 index 00000000..d1ae4898 --- /dev/null +++ b/NetEvent/Server/Models/EventTicketType.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace NetEvent.Server.Models; + +public class EventTicketType +{ + [Key] + public long? Id { get; set; } + + public string? Name { get; set; } + + public string? Slug { get; set; } + + public int Price { get; set; } + + public Currency Currency { get; set; } + + public long AvailableTickets { get; set; } + + public DateTime SellStartDate { get; set; } + + public DateTime SellEndDate { get; set; } + + public bool IsGiftable { get; set; } + + public long? EventId { get; set; } + + [ForeignKey(nameof(EventId))] + public Event? Event { get; set; } +} diff --git a/NetEvent/Server/Models/Payment.cs b/NetEvent/Server/Models/Payment.cs new file mode 100644 index 00000000..22d8c5f6 --- /dev/null +++ b/NetEvent/Server/Models/Payment.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace NetEvent.Server.Models; + +public class Payment +{ + [Key] + public long? Id { get; set; } + + public DateTime PaymentDate { get; set; } + + public long? PurchaseId { get; set; } + + [ForeignKey(nameof(PurchaseId))] + public Purchase? Purchase { get; set; } +} diff --git a/NetEvent/Server/Models/PaymentStatus.cs b/NetEvent/Server/Models/PaymentStatus.cs new file mode 100644 index 00000000..c4531193 --- /dev/null +++ b/NetEvent/Server/Models/PaymentStatus.cs @@ -0,0 +1,7 @@ +namespace NetEvent.Server.Models; + +public enum PaymentStatus +{ + Pending, + Payed, +} diff --git a/NetEvent/Server/Models/Purchase.cs b/NetEvent/Server/Models/Purchase.cs new file mode 100644 index 00000000..eea45279 --- /dev/null +++ b/NetEvent/Server/Models/Purchase.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; + +namespace NetEvent.Server.Models; + +public class Purchase +{ + [Key] + public string? Id { get; set; } + + public DateTime? PurchaseTime { get; set; } + + public string? UserId { get; set; } + + [ForeignKey(nameof(UserId))] + public ApplicationUser? User { get; set; } + + [InverseProperty(nameof(TicketPurchase.Purchase))] + public IList? TicketPurchases { get; set; } + + public int Price => TicketPurchases?.Sum(x => x.Price) ?? 0; +} diff --git a/NetEvent/Server/Models/Refund.cs b/NetEvent/Server/Models/Refund.cs new file mode 100644 index 00000000..fef3a7b1 --- /dev/null +++ b/NetEvent/Server/Models/Refund.cs @@ -0,0 +1,12 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace NetEvent.Server.Models; + +public class Refund +{ + [Key] + public long? Id { get; set; } + + public DateTime RefundDate { get; set; } +} diff --git a/NetEvent/Server/Models/RefundStatus.cs b/NetEvent/Server/Models/RefundStatus.cs new file mode 100644 index 00000000..6b3d9888 --- /dev/null +++ b/NetEvent/Server/Models/RefundStatus.cs @@ -0,0 +1,7 @@ +namespace NetEvent.Server.Models; + +public enum RefundStatus +{ + Pending, + Refunded, +} diff --git a/NetEvent/Server/Models/SystemInfo.cs b/NetEvent/Server/Models/SystemInfo.cs index a96ddb53..dda7ff63 100644 --- a/NetEvent/Server/Models/SystemInfo.cs +++ b/NetEvent/Server/Models/SystemInfo.cs @@ -4,10 +4,10 @@ namespace NetEvent.Server.Models { public class SystemInfo { - public List? Components { get; set; } + public IList? Components { get; set; } - public List? Health { get; set; } + public IList? Health { get; set; } - public List? Versions { get; set; } + public IList? Versions { get; set; } } } diff --git a/NetEvent/Server/Models/TicketPurchase.cs b/NetEvent/Server/Models/TicketPurchase.cs new file mode 100644 index 00000000..328ba6da --- /dev/null +++ b/NetEvent/Server/Models/TicketPurchase.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace NetEvent.Server.Models; + +public class TicketPurchase +{ + [Key] + public long? Id { get; set; } + + public long? TicketId { get; set; } + + [ForeignKey(nameof(TicketId))] + public EventTicketType? Ticket { get; set; } + + public string? PurchaseId { get; set; } + + [ForeignKey(nameof(PurchaseId))] + public Purchase? Purchase { get; set; } + + public int Price { get; set; } + + public Currency Currency { get; set; } +} diff --git a/NetEvent/Server/Models/TicketPurchaseRefund.cs b/NetEvent/Server/Models/TicketPurchaseRefund.cs new file mode 100644 index 00000000..33ac5023 --- /dev/null +++ b/NetEvent/Server/Models/TicketPurchaseRefund.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace NetEvent.Server.Models; + +public class TicketPurchaseRefund +{ + [Key] + public long? Id { get; set; } + + public long? RefundId { get; set; } + + [ForeignKey(nameof(RefundId))] + public Refund? Refund { get; set; } + + public long? TicketPurchaseId { get; set; } + + [ForeignKey(nameof(TicketPurchaseId))] + public TicketPurchase? TicketPurchase { get; set; } +} diff --git a/NetEvent/Server/Modules/Events/Endpoints/DeleteEventTicketType.cs b/NetEvent/Server/Modules/Events/Endpoints/DeleteEventTicketType.cs new file mode 100644 index 00000000..9595614f --- /dev/null +++ b/NetEvent/Server/Modules/Events/Endpoints/DeleteEventTicketType.cs @@ -0,0 +1,53 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using NetEvent.Server.Data.Events; + +namespace NetEvent.Server.Modules.Events.Endpoints +{ + public static class DeleteEventTicketType + { + public sealed class Handler : IRequestHandler + { + private readonly IEventManager _EventManager; + + public Handler(IEventManager eventManager) + { + _EventManager = eventManager; + } + + public async Task Handle(Request request, CancellationToken cancellationToken) + { + var result = await _EventManager.DeleteTicketAsync(request.EventTicketTypeId).ConfigureAwait(false); + if (!result.Succeeded) + { + return new Response(ReturnType.Error, string.Join(Environment.NewLine, result.Errors)); + } + + return new Response(); + } + } + + public sealed class Request : IRequest + { + public Request(long eventTicketTypeId) + { + EventTicketTypeId = eventTicketTypeId; + } + + public long EventTicketTypeId { get; } + } + + public sealed class Response : ResponseBase + { + public Response() + { + } + + public Response(ReturnType returnType, string error) : base(returnType, error) + { + } + } + } +} diff --git a/NetEvent/Server/Modules/Events/Endpoints/GetEvent.cs b/NetEvent/Server/Modules/Events/Endpoints/GetEvent.cs index 2c6bfa50..b6b09615 100644 --- a/NetEvent/Server/Modules/Events/Endpoints/GetEvent.cs +++ b/NetEvent/Server/Modules/Events/Endpoints/GetEvent.cs @@ -1,8 +1,8 @@ -using System; -using System.Linq; +using System.Linq; using System.Threading; using System.Threading.Tasks; using MediatR; +using Microsoft.EntityFrameworkCore; using NetEvent.Server.Data; using NetEvent.Shared; using NetEvent.Shared.Dto.Event; @@ -25,11 +25,11 @@ public async Task Handle(Request request, CancellationToken cancellati Models.Event? eventModel; if (request.Slug != null) { - eventModel = _DbContext.Events.Where(e => e.Slug != null && e.Slug.Equals(request.Slug, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + eventModel = await _DbContext.Events.Where(e => e.Slug == request.Slug).Include(e => e.TicketTypes).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); } else { - eventModel = await _DbContext.Events.FindAsync(new object[] { request.Id }, cancellationToken); + eventModel = await _DbContext.Events.Where(x => x.Id == request.Id).Include(e => e.TicketTypes).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); } if (eventModel == null) diff --git a/NetEvent/Server/Modules/Events/Endpoints/GetEventTicketType.cs b/NetEvent/Server/Modules/Events/Endpoints/GetEventTicketType.cs new file mode 100644 index 00000000..e700f7c1 --- /dev/null +++ b/NetEvent/Server/Modules/Events/Endpoints/GetEventTicketType.cs @@ -0,0 +1,75 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using Microsoft.EntityFrameworkCore; +using NetEvent.Server.Data; +using NetEvent.Shared; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Server.Modules.Events.Endpoints +{ + public static class GetEventTicketType + { + public sealed class Handler : IRequestHandler + { + private readonly ApplicationDbContext _DbContext; + + public Handler(ApplicationDbContext dbContext) + { + _DbContext = dbContext; + } + + public async Task Handle(Request request, CancellationToken cancellationToken) + { + Models.EventTicketType? eventTicketTypeModel; + if (request.Slug != null) + { + eventTicketTypeModel = await _DbContext.Tickets.Where(e => e.Slug != null && e.Slug.Equals(request.Slug, StringComparison.OrdinalIgnoreCase)).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); + } + else + { + eventTicketTypeModel = await _DbContext.Tickets.Where(x => x.Id == request.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); + } + + if (eventTicketTypeModel == null) + { + return new Response(ReturnType.NotFound, "Event for Id not found!"); + } + + var convertedEventTicketType = eventTicketTypeModel.ToEventTicketTypeDto(); + + return new Response(convertedEventTicketType); + } + } + + public sealed class Request : IRequest + { + public Request(long id) + { + Id = id; + } + + public Request(string slug) + { + Slug = slug; + } + + public long Id { get; } + + public string? Slug { get; } + } + + public sealed class Response : ResponseBase + { + public Response(EventTicketTypeDto? value) : base(value) + { + } + + public Response(ReturnType returnType, string error) : base(returnType, error) + { + } + } + } +} diff --git a/NetEvent/Server/Modules/Events/Endpoints/PostEventTicketType.cs b/NetEvent/Server/Modules/Events/Endpoints/PostEventTicketType.cs new file mode 100644 index 00000000..0b75bad5 --- /dev/null +++ b/NetEvent/Server/Modules/Events/Endpoints/PostEventTicketType.cs @@ -0,0 +1,61 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using NetEvent.Server.Data.Events; +using NetEvent.Shared; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Server.Modules.Events.Endpoints +{ + public static class PostEventTicketType + { + public sealed class Handler : IRequestHandler + { + private readonly IEventManager _EventManager; + + public Handler(IEventManager eventManager) + { + _EventManager = eventManager; + } + + public async Task Handle(Request request, CancellationToken cancellationToken) + { + var newEventTicketType = request.EventTicketType.ToEventTicketType(); + newEventTicketType.EventId = request.EventId; + + var result = await _EventManager.CreateTicketAsync(newEventTicketType).ConfigureAwait(false); + if (!result.Succeeded || newEventTicketType.Id == null) + { + return new Response(ReturnType.Error, string.Join(Environment.NewLine, result.Errors)); + } + + return new Response(newEventTicketType.Id!.Value); + } + } + + public sealed class Request : IRequest + { + public Request(long eventId, EventTicketTypeDto eventTicketTypeDto) + { + EventId = eventId; + EventTicketType = eventTicketTypeDto; + } + + public long EventId { get; } + + public EventTicketTypeDto EventTicketType { get; } + } + + public sealed class Response : ResponseBase + { + public Response(long createdEventTicketTypeId) : base(createdEventTicketTypeId) + { + } + + public Response(ReturnType returnType, string error) : base(returnType, error) + { + } + } + } +} diff --git a/NetEvent/Server/Modules/Events/Endpoints/PutEventTicketType.cs b/NetEvent/Server/Modules/Events/Endpoints/PutEventTicketType.cs new file mode 100644 index 00000000..bf1e0903 --- /dev/null +++ b/NetEvent/Server/Modules/Events/Endpoints/PutEventTicketType.cs @@ -0,0 +1,61 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using NetEvent.Server.Data.Events; +using NetEvent.Shared; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Server.Modules.Events.Endpoints +{ + public static class PutEventTicketType + { + public sealed class Handler : IRequestHandler + { + private readonly IEventManager _EventManager; + + public Handler(IEventManager eventManager) + { + _EventManager = eventManager; + } + + public async Task Handle(Request request, CancellationToken cancellationToken) + { + var newEventTicketType = request.EventTicketType.ToEventTicketType(); + var result = await _EventManager.UpdateTicketAsync(newEventTicketType).ConfigureAwait(false); + if (!result.Succeeded) + { + return new Response(ReturnType.Error, string.Join(Environment.NewLine, result.Errors)); + } + + return new Response(newEventTicketType.ToEventTicketTypeDto()); + } + } + + public sealed class Request : IRequest + { + public Request(long id, EventTicketTypeDto eventTicketTypeDto) + { + Guard.IsNotNull(eventTicketTypeDto, nameof(eventTicketTypeDto)); + + Id = id; + EventTicketType = eventTicketTypeDto; + } + + public long Id { get; } + + public EventTicketTypeDto EventTicketType { get; } + } + + public sealed class Response : ResponseBase + { + public Response(EventTicketTypeDto createdEventTicketType) : base(createdEventTicketType) + { + } + + public Response(ReturnType returnType, string error) : base(returnType, error) + { + } + } + } +} diff --git a/NetEvent/Server/Modules/Events/EventsModule.cs b/NetEvent/Server/Modules/Events/EventsModule.cs index 116a9d2c..2f627914 100644 --- a/NetEvent/Server/Modules/Events/EventsModule.cs +++ b/NetEvent/Server/Modules/Events/EventsModule.cs @@ -24,10 +24,17 @@ public override IEndpointRouteBuilder MapModuleEndpoints(IEndpointRouteBuilder e public override IEndpointRouteBuilder MapModuleWriteAuthEndpoints(IEndpointRouteBuilder endpoints) { + // BaseRoute: /api/events endpoints.MapPost("/", async ([FromBody] EventDto eventDto, [FromServices] IMediator m) => ToApiResult(await m.Send(new PostEvent.Request(eventDto)))); endpoints.MapPut("/{eventId}", async ([FromRoute] long eventId, [FromBody] EventDto eventDto, [FromServices] IMediator m) => ToApiResult(await m.Send(new PutEvent.Request(eventId, eventDto)))); endpoints.MapDelete("/{eventId}", async ([FromRoute] long eventId, [FromServices] IMediator m) => ToApiResult(await m.Send(new DeleteEvent.Request(eventId)))); + var ticketTypeEndPoints = endpoints.MapGroup("/tickettype"); + ticketTypeEndPoints.MapPost("/{eventId}", async ([FromRoute] long eventId, [FromBody] EventTicketTypeDto eventTicketTypeDto, [FromServices] IMediator m) => ToApiResult(await m.Send(new PostEventTicketType.Request(eventId, eventTicketTypeDto)))); + ticketTypeEndPoints.MapPut("/{eventTicketTypeId}", async ([FromRoute] long eventTicketTypeId, [FromBody] EventTicketTypeDto eventTicketTypeDto, [FromServices] IMediator m) => ToApiResult(await m.Send(new PutEventTicketType.Request(eventTicketTypeId, eventTicketTypeDto)))); + ticketTypeEndPoints.MapDelete("/{eventTicketTypeId}", async ([FromRoute] long eventTicketTypeId, [FromServices] IMediator m) => ToApiResult(await m.Send(new DeleteEventTicketType.Request(eventTicketTypeId)))); + ticketTypeEndPoints.MapGet("/{eventTicketTypeId}", async ([FromRoute] long eventTicketTypeId, [FromServices] IMediator m) => ToApiResult(await m.Send(new GetEventTicketType.Request(eventTicketTypeId)))); + return base.MapModuleWriteAuthEndpoints(endpoints); } @@ -37,6 +44,11 @@ public override void OnModelCreating(ModelBuilder builder) { entity.ToTable(name: "Events"); }); + + builder.Entity(entity => + { + entity.ToTable(name: "EventTicketTypes"); + }); } } } diff --git a/NetEvent/Server/Modules/Payment/Endpoints/GetPaymentMethods.cs b/NetEvent/Server/Modules/Payment/Endpoints/GetPaymentMethods.cs new file mode 100644 index 00000000..1531cb68 --- /dev/null +++ b/NetEvent/Server/Modules/Payment/Endpoints/GetPaymentMethods.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using NetEvent.Server.Data; +using NetEvent.Shared; +using NetEvent.Shared.Dto; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Server.Modules.Payment.Endpoints +{ + public static class GetPaymentMethods + { + public sealed class Handler : IRequestHandler + { + private readonly IPaymentManager _PaymentManager; + + public Handler(IPaymentManager paymentManager) + { + _PaymentManager = paymentManager; + } + + public async Task Handle(Request request, CancellationToken cancellationToken) + { + var paymentMethodResponse = await _PaymentManager.GetPaymentMethodsAsync(request.Amount, request.Currency); + var result = paymentMethodResponse.PaymentMethods.Select(x => x.ToPaymentMethodDto()).ToList(); + + return new Response(result); + } + } + + public sealed class Request : IRequest + { + public Request(long amount, CurrencyDto currency) + { + Amount = amount; + Currency = currency; + } + + public CurrencyDto Currency { get; } + + public long Amount { get; } + } + + public sealed class Response : ResponseBase> + { + public Response(IReadOnlyCollection response) : base(response) + { + } + + public Response(ReturnType returnType, string error) : base(returnType, error) + { + } + } + } +} diff --git a/NetEvent/Server/Modules/Payment/Endpoints/PostCart.cs b/NetEvent/Server/Modules/Payment/Endpoints/PostCart.cs new file mode 100644 index 00000000..d79cb01b --- /dev/null +++ b/NetEvent/Server/Modules/Payment/Endpoints/PostCart.cs @@ -0,0 +1,55 @@ +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using NetEvent.Server.Data; +using NetEvent.Shared; +using NetEvent.Shared.Dto; + +namespace NetEvent.Server.Modules.Payment.Endpoints +{ + public static class PostCart + { + public sealed class Handler : IRequestHandler + { + private readonly IPaymentManager _PaymentManager; + + public Handler(IPaymentManager paymentManager) + { + _PaymentManager = paymentManager; + } + + public async Task Handle(Request request, CancellationToken cancellationToken) + { + var purchase = await _PaymentManager.PurchaseAsync(request.CartDto, request.User); + var result = purchase.ToPurchaseDto(); + + return new Response(result); + } + } + + public sealed class Request : IRequest + { + public Request(CartDto cartDto, ClaimsPrincipal user) + { + CartDto = cartDto; + User = user; + } + + public CartDto CartDto { get; } + + public ClaimsPrincipal User { get; } + } + + public sealed class Response : ResponseBase + { + public Response(PurchaseDto response) : base(response) + { + } + + public Response(ReturnType returnType, string error) : base(returnType, error) + { + } + } + } +} diff --git a/NetEvent/Server/Modules/Payment/Endpoints/PostDropInData.cs b/NetEvent/Server/Modules/Payment/Endpoints/PostDropInData.cs new file mode 100644 index 00000000..867c4734 --- /dev/null +++ b/NetEvent/Server/Modules/Payment/Endpoints/PostDropInData.cs @@ -0,0 +1,59 @@ +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using NetEvent.Server.Data; +using NetEvent.Shared.Dto; +using Json = System.Text.Json; + +namespace NetEvent.Server.Modules.Payment.Endpoints +{ + public static class PostDropInData + { + public sealed class Handler : IRequestHandler + { + private readonly IPaymentManager _PaymentManager; + + public Handler(IPaymentManager paymentManager) + { + _PaymentManager = paymentManager; + } + + public async Task Handle(Request request, CancellationToken cancellationToken) + { + var paymentResponse = await _PaymentManager.SubmitDropInEventDataAsync(request.User, request.PurchaseId, request.PaymentMethodData); + + var paymentResponseJson = Json.JsonSerializer.Serialize(paymentResponse); + var result = new PaymentResponseDto { PaymentResponseJson = paymentResponseJson }; + return new Response(result); + } + } + + public sealed class Request : IRequest + { + public Request(ClaimsPrincipal user, string purchaseId, string paymentMethodData) + { + User = user; + PurchaseId = purchaseId; + PaymentMethodData = paymentMethodData; + } + + public ClaimsPrincipal User { get; } + + public string PaymentMethodData { get; internal set; } + + public string PurchaseId { get; internal set; } + } + + public sealed class Response : ResponseBase + { + public Response(PaymentResponseDto response) : base(response) + { + } + + public Response(ReturnType returnType, string error) : base(returnType, error) + { + } + } + } +} diff --git a/NetEvent/Server/Modules/Payment/PaymentModule.cs b/NetEvent/Server/Modules/Payment/PaymentModule.cs new file mode 100644 index 00000000..5a86b718 --- /dev/null +++ b/NetEvent/Server/Modules/Payment/PaymentModule.cs @@ -0,0 +1,47 @@ +using System.Security.Claims; +using MediatR; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using Microsoft.EntityFrameworkCore; +using NetEvent.Server.Models; +using NetEvent.Server.Modules; +using NetEvent.Server.Modules.Payment.Endpoints; +using NetEvent.Shared.Dto; +using NetEvent.Shared.Dto.Event; + +namespace NetVenue.Server.Modules.Payment +{ + public class PaymentModule : ModuleBase + { + public override IEndpointRouteBuilder MapModuleEndpoints(IEndpointRouteBuilder endpoints) + { + // BaseRoute: /api/payment + endpoints.MapGet("/paymentmethods/{amount:long}/{currency}", async ([FromRoute] long amount, [FromRoute] CurrencyDto currency, [FromServices] IMediator m) => ToApiResult(await m.Send(new GetPaymentMethods.Request(amount, currency)))); + endpoints.MapPost("/checkout/buy", async ([FromBody] CartDto cartDto, ClaimsPrincipal user, [FromServices] IMediator m) => ToApiResult(await m.Send(new PostCart.Request(cartDto, user)))); + endpoints.MapPost("/checkout/{purchaseId}/payments", async ([FromRoute] string purchaseId, [FromBody] string paymentMethodData, ClaimsPrincipal user, [FromServices] IMediator m) => ToApiResult(await m.Send(new PostDropInData.Request(user, purchaseId, paymentMethodData)))); + endpoints.MapPost("/checkout/{purchaseId}/payments/details", async ([FromRoute] string purchaseId, [FromBody] string paymentMethodData, ClaimsPrincipal user, [FromServices] IMediator m) => ToApiResult(await m.Send(new PostDropInData.Request(user, purchaseId, paymentMethodData)))); + + //endpoints.MapGet("/{venueId:long}", async ([FromRoute] long venueId, [FromServices] IMediator m) => ToApiResult(await m.Send(new GetVenue.Request(venueId)))); + //endpoints.MapGet("/{slug}", async ([FromRoute] string slug, [FromServices] IMediator m) => ToApiResult(await m.Send(new GetVenue.Request(slug)))); + //endpoints.MapGet("/", async ([FromServices] IMediator m) => ToApiResult(await m.Send(new GetVenues.Request()))); + //endpoints.MapPost("/", async ([FromBody] VenueDto venueDto, [FromServices] IMediator m) => ToApiResult(await m.Send(new PostVenue.Request(venueDto)))); + //endpoints.MapPut("/{venueId}", async ([FromRoute] long venueId, [FromBody] VenueDto venueDto, [FromServices] IMediator m) => ToApiResult(await m.Send(new PutVenue.Request(venueId, venueDto)))); + //endpoints.MapDelete("/{venueId}", async ([FromRoute] long venueId, [FromServices] IMediator m) => ToApiResult(await m.Send(new DeleteVenue.Request(venueId)))); + + return endpoints; + } + + public override void OnModelCreating(ModelBuilder builder) + { + builder.Entity(entity => + { + entity.ToTable(name: "Purchases"); + }); + builder.Entity(entity => + { + entity.ToTable(name: "TicketPurchases"); + }); + } + } +} diff --git a/NetEvent/Server/NetEvent.Server.csproj b/NetEvent/Server/NetEvent.Server.csproj index 8aea3a3b..79fa3d94 100644 --- a/NetEvent/Server/NetEvent.Server.csproj +++ b/NetEvent/Server/NetEvent.Server.csproj @@ -7,6 +7,7 @@ NetEvent.Server-22C6183C-4927-4801-90E6-4AC1E79183B5 true 0.0.1 + true @@ -14,6 +15,7 @@ + diff --git a/NetEvent/Server/Program.cs b/NetEvent/Server/Program.cs index 358d871e..5cc78914 100644 --- a/NetEvent/Server/Program.cs +++ b/NetEvent/Server/Program.cs @@ -103,6 +103,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddSingleton(); @@ -124,6 +125,11 @@ builder.Services.TryAddScoped(); } +builder.Services.AddResponseCompression(options => +{ + options.EnableForHttps = true; +}); + builder.WebHost.UseStaticWebAssets(); var app = builder.Build(); @@ -150,6 +156,7 @@ app.UseHsts(); } +app.UseResponseCompression(); app.UseHttpsRedirection(); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/NetEvent/Shared.Tests/NetEvent.Shared.Tests.csproj b/NetEvent/Shared.Tests/NetEvent.Shared.Tests.csproj index e422161d..d572a630 100644 --- a/NetEvent/Shared.Tests/NetEvent.Shared.Tests.csproj +++ b/NetEvent/Shared.Tests/NetEvent.Shared.Tests.csproj @@ -9,6 +9,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/NetEvent/Shared/Config/BooleanValueType.cs b/NetEvent/Shared/Config/BooleanValueType.cs index 4a14a844..859c28e5 100644 --- a/NetEvent/Shared/Config/BooleanValueType.cs +++ b/NetEvent/Shared/Config/BooleanValueType.cs @@ -1,4 +1,6 @@ -namespace NetEvent.Shared.Config +using System.Globalization; + +namespace NetEvent.Shared.Config { public class BooleanValueType : ValueType { @@ -6,7 +8,7 @@ public BooleanValueType(bool defaultValue) : base(defaultValue) { } - public override string DefaultValueSerialized => DefaultValue.ToString(); + public override string DefaultValueSerialized => DefaultValue.ToString(CultureInfo.InvariantCulture); public override bool IsValid(bool value) => true; diff --git a/NetEvent/Shared/Config/SystemSettingGroup.cs b/NetEvent/Shared/Config/SystemSettingGroup.cs index 4a5b37fc..6dabd466 100644 --- a/NetEvent/Shared/Config/SystemSettingGroup.cs +++ b/NetEvent/Shared/Config/SystemSettingGroup.cs @@ -5,5 +5,6 @@ public enum SystemSettingGroup OrganizationData, AuthenticationData, StyleData, + PaymentData, } } diff --git a/NetEvent/Shared/Config/SystemSettings.cs b/NetEvent/Shared/Config/SystemSettings.cs index f792550c..0455f5f0 100644 --- a/NetEvent/Shared/Config/SystemSettings.cs +++ b/NetEvent/Shared/Config/SystemSettings.cs @@ -13,6 +13,7 @@ private SystemSettings() new OrganizationData(), new StyleData(), new AuthenticationData(), + new PaymentData(), }; } @@ -56,6 +57,20 @@ public AuthenticationData() : base(SystemSettingGroup.AuthenticationData) } } + public class PaymentData : SettingGroupBase + { + public const string AdyenApiKey = "AdyenApiKey"; + public const string AdyenClientKey = "AdyenClientKey"; + public const string AdyenMerchantAccount = "AdyenMerchantAccount"; + + public PaymentData() : base(SystemSettingGroup.PaymentData) + { + CreateSystemSettingWithHint(AdyenApiKey, new StringValueType(string.Empty)); + CreateSystemSettingWithHint(AdyenClientKey, new StringValueType(string.Empty)); + CreateSystemSettingWithHint(AdyenMerchantAccount, new StringValueType(string.Empty)); + } + } + public class StyleData : SettingGroupBase { public const string PrimaryColor = "PrimaryColor"; diff --git a/NetEvent/Shared/Dto/CartDto.cs b/NetEvent/Shared/Dto/CartDto.cs new file mode 100644 index 00000000..d5718819 --- /dev/null +++ b/NetEvent/Shared/Dto/CartDto.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace NetEvent.Shared.Dto; + +public class CartDto +{ + [JsonPropertyName("cartentries")] + public IReadOnlyList CartEntries { get; set; } = Array.Empty(); +} diff --git a/NetEvent/Shared/Dto/CartEntryDto.cs b/NetEvent/Shared/Dto/CartEntryDto.cs new file mode 100644 index 00000000..797720c3 --- /dev/null +++ b/NetEvent/Shared/Dto/CartEntryDto.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace NetEvent.Shared.Dto; + +public class CartEntryDto +{ + [JsonPropertyName("amount")] + public int Amount { get; set; } + + [JsonPropertyName("ticketId")] + public long? TicketId { get; set; } +} diff --git a/NetEvent/Shared/Dto/CheckoutSessionDto.cs b/NetEvent/Shared/Dto/CheckoutSessionDto.cs new file mode 100644 index 00000000..9c0e4126 --- /dev/null +++ b/NetEvent/Shared/Dto/CheckoutSessionDto.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace NetEvent.Shared.Dto; + +public class CheckoutSessionDto +{ + [JsonPropertyName("id")] + public string? Id { get; set; } + + [JsonPropertyName("sessionData")] + public string? SessionData { get; set; } +} diff --git a/NetEvent/Shared/Dto/Event/CurrencyDto.cs b/NetEvent/Shared/Dto/Event/CurrencyDto.cs new file mode 100644 index 00000000..c86b7736 --- /dev/null +++ b/NetEvent/Shared/Dto/Event/CurrencyDto.cs @@ -0,0 +1,7 @@ +namespace NetEvent.Shared.Dto.Event +{ + public enum CurrencyDto + { + Euro, + } +} diff --git a/NetEvent/Shared/Dto/Event/CurrencyExtension.cs b/NetEvent/Shared/Dto/Event/CurrencyExtension.cs new file mode 100644 index 00000000..ff0dc1e4 --- /dev/null +++ b/NetEvent/Shared/Dto/Event/CurrencyExtension.cs @@ -0,0 +1,45 @@ +using System; + +namespace NetEvent.Shared.Dto.Event +{ + public static class CurrencyExtension + { + private const double _CurrencyBaseFactor = 100d; + + public static string ToSymbol(this CurrencyDto currency) + { + return currency switch + { + CurrencyDto.Euro => "€", + _ => throw new NotSupportedException($"The Currency {currency} is not implemented!"), + }; + } + + public static string To3DigitIso(this CurrencyDto currency) + { + return currency switch + { + CurrencyDto.Euro => "EUR", + _ => throw new NotSupportedException($"The Currency {currency} is not implemented!"), + }; + } + + public static int ToCurrencyBaseValue(this CurrencyDto currency, double value) + { + return currency switch + { + CurrencyDto.Euro => (int)(value * _CurrencyBaseFactor), + _ => throw new NotSupportedException($"The Currency {currency} is not implemented!"), + }; + } + + public static double ToCurrencyValue(this CurrencyDto currency, int baseValue) + { + return currency switch + { + CurrencyDto.Euro => baseValue / _CurrencyBaseFactor, + _ => throw new NotSupportedException($"The Currency {currency} is not implemented!"), + }; + } + } +} diff --git a/NetEvent/Shared/Dto/Event/EventDto.cs b/NetEvent/Shared/Dto/Event/EventDto.cs index 19aa703b..337e1c4b 100644 --- a/NetEvent/Shared/Dto/Event/EventDto.cs +++ b/NetEvent/Shared/Dto/Event/EventDto.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; namespace NetEvent.Shared.Dto.Event { @@ -25,5 +27,7 @@ public class EventDto public string? Description { get; set; } public EventFormatDto EventFormat { get; set; } + + public ICollection? TicketTypes { get; set; } = new Collection(); } } diff --git a/NetEvent/Shared/Dto/Event/EventTicketTypeDto.cs b/NetEvent/Shared/Dto/Event/EventTicketTypeDto.cs new file mode 100644 index 00000000..dd3f14c2 --- /dev/null +++ b/NetEvent/Shared/Dto/Event/EventTicketTypeDto.cs @@ -0,0 +1,25 @@ +using System; + +namespace NetEvent.Shared.Dto.Event +{ + public class EventTicketTypeDto + { + public long? Id { get; set; } + + public string? Name { get; set; } + + public string? Slug { get; set; } + + public int Price { get; set; } + + public CurrencyDto Currency { get; set; } + + public long AvailableTickets { get; set; } + + public DateTime? SellStartDate { get; set; } + + public DateTime? SellEndDate { get; set; } + + public bool IsGiftable { get; set; } + } +} diff --git a/NetEvent/Shared/Dto/PaymentMethodDto.cs b/NetEvent/Shared/Dto/PaymentMethodDto.cs new file mode 100644 index 00000000..5ad021e5 --- /dev/null +++ b/NetEvent/Shared/Dto/PaymentMethodDto.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace NetEvent.Shared.Dto; + +public class PaymentMethodDto +{ + [JsonPropertyName("brand")] + public string? Brand { get; set; } + + [JsonPropertyName("brands")] + public IReadOnlyList Brands { get; set; } + + [JsonPropertyName("configuration")] + public Dictionary Configuration { get; set; } + + [JsonPropertyName("group")] + public PaymentMethodGroupDto Group { get; set; } + + [JsonPropertyName("issuers")] + public IReadOnlyList Issuers { get; set; } + + [JsonPropertyName("name")] + public string? Name { get; set; } + + [JsonPropertyName("type")] + public string? Type { get; set; } +} diff --git a/NetEvent/Shared/Dto/PaymentMethodGroupDto.cs b/NetEvent/Shared/Dto/PaymentMethodGroupDto.cs new file mode 100644 index 00000000..716ed3c8 --- /dev/null +++ b/NetEvent/Shared/Dto/PaymentMethodGroupDto.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace NetEvent.Shared.Dto; + +public class PaymentMethodGroupDto +{ + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("paymentMethodData")] + public string PaymentMethodData { get; set; } + + [JsonPropertyName("type")] + public string Type { get; set; } +} diff --git a/NetEvent/Shared/Dto/PaymentMethodIssuerDto.cs b/NetEvent/Shared/Dto/PaymentMethodIssuerDto.cs new file mode 100644 index 00000000..5c9775d6 --- /dev/null +++ b/NetEvent/Shared/Dto/PaymentMethodIssuerDto.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace NetEvent.Shared.Dto; + +public class PaymentMethodIssuerDto +{ + [JsonPropertyName("disabled")] + public bool Disabled { get; set; } + + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("name")] + public string Name { get; set; } +} diff --git a/NetEvent/Shared/Dto/PaymentResponseDto.cs b/NetEvent/Shared/Dto/PaymentResponseDto.cs new file mode 100644 index 00000000..f2f40cc3 --- /dev/null +++ b/NetEvent/Shared/Dto/PaymentResponseDto.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace NetEvent.Shared.Dto; + +public class PaymentResponseDto +{ + [JsonPropertyName("paymentResponseJson")] + public string PaymentResponseJson { get; set; } +} diff --git a/NetEvent/Shared/Dto/PurchaseDto.cs b/NetEvent/Shared/Dto/PurchaseDto.cs new file mode 100644 index 00000000..19f4a740 --- /dev/null +++ b/NetEvent/Shared/Dto/PurchaseDto.cs @@ -0,0 +1,23 @@ +using System; + +using System.Text.Json.Serialization; + +namespace NetEvent.Shared.Dto; + +public class PurchaseDto +{ + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("purchaseTime")] + public DateTime? PurchaseTime { get; set; } + + [JsonPropertyName("userId")] + public string? UserId { get; set; } + + //[InverseProperty(nameof(TicketPurchase.Purchase))] + //public List? TicketPurchases { get; set; } + + [JsonPropertyName("price")] + public int Price { get; set; } +} diff --git a/NetEvent/Shared/Dto/SystemInfoDto.cs b/NetEvent/Shared/Dto/SystemInfoDto.cs index 0fa9c01b..f0941c42 100644 --- a/NetEvent/Shared/Dto/SystemInfoDto.cs +++ b/NetEvent/Shared/Dto/SystemInfoDto.cs @@ -8,17 +8,17 @@ public SystemInfoDto() { } - public SystemInfoDto(List components, List health, List versions) + public SystemInfoDto(IReadOnlyList components, IReadOnlyList health, IReadOnlyList versions) { Components = components; Health = health; Versions = versions; } - public List Components { get; set; } = default!; + public IReadOnlyList Components { get; set; } = default!; - public List Health { get; set; } = default!; + public IReadOnlyList Health { get; set; } = default!; - public List Versions { get; set; } = default!; + public IReadOnlyList Versions { get; set; } = default!; } } diff --git a/NetEvent/Shared/Validators/EventTicketTypeModelFluentValidator.cs b/NetEvent/Shared/Validators/EventTicketTypeModelFluentValidator.cs new file mode 100644 index 00000000..19d803cf --- /dev/null +++ b/NetEvent/Shared/Validators/EventTicketTypeModelFluentValidator.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FluentValidation; +using NetEvent.Shared.Dto.Event; + +namespace NetEvent.Shared.Validators +{ + public class EventTicketTypeModelFluentValidator : AbstractValidator + { + private const int _MaxNameLength = 100; + + public EventTicketTypeModelFluentValidator() + { + RuleFor(x => x.Name) + .NotEmpty() + .Length(1, _MaxNameLength); + + RuleFor(x => x.Price) + .GreaterThanOrEqualTo(0); + + RuleFor(x => x.AvailableTickets) + .GreaterThan(0); + + RuleFor(x => x.SellEndDate) + .GreaterThan(x => x.SellStartDate); + + RuleFor(x => x.SellStartDate) + .NotNull(); + } + + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((EventTicketTypeDto)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + { + return Array.Empty(); + } + + return result.Errors.Select(e => e.ErrorMessage); + }; + } +} diff --git a/NetEvent/TestHelper/Fakers.cs b/NetEvent/TestHelper/Fakers.cs index 4e1dca5f..c2fc30c3 100644 --- a/NetEvent/TestHelper/Fakers.cs +++ b/NetEvent/TestHelper/Fakers.cs @@ -1,5 +1,8 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Linq; using Bogus; using NetEvent.Server.Models; using NetEvent.Shared.Dto; @@ -53,6 +56,20 @@ public static class Fakers .RuleFor(e => e.Venue, (f, e) => venues.ElementAtOrDefault(Random.Shared.Next(venues.Count() - 1))) .RuleFor(e => e.VenueId, (f, e) => e.Venue?.Id ?? 0); + public static Faker EventTicketTypeFaker(IEnumerable events) => new Faker() + .RuleFor(v => v.Id, (f, v) => f.IndexFaker) + .RuleFor(e => e.Name, (f, e) => f.Name.FirstName()) + .RuleFor(e => e.Slug, (f, e) => new SlugHelper().GenerateSlug(e.Name)) + .RuleFor(e => e.Price, (f, e) => f.Random.Int(0)) + .RuleFor(e => e.Currency, (f, e) => Currency.Euro) + .RuleFor(e => e.AvailableTickets, (f, e) => f.Random.Int(1)) + .RuleFor(e => e.SellStartDate, (f, e) => DateTime.UtcNow.AddDays(Random.Shared.Next(1, 30))) + .RuleFor(e => e.SellEndDate, (f, e) => e.SellStartDate.AddDays(Random.Shared.Next(1, 30))) + .RuleFor(e => e.IsGiftable, (f, e) => f.Random.Bool()) + .RuleFor(e => e.Event, (f, e) => events.ElementAtOrDefault(Random.Shared.Next(events.Count() - 1))) + .RuleFor(e => e.EventId, (f, e) => e.Event?.Id); + + public static Faker VenueFaker() => new Faker() .RuleFor(v => v.Id, (f, v) => f.IndexFaker) .RuleFor(v => v.Name, (f, v) => f.Name.FirstName()) diff --git a/NetEvent/TestHelper/NetEvent.TestHelper.csproj b/NetEvent/TestHelper/NetEvent.TestHelper.csproj index eee22aff..02fe716a 100644 --- a/NetEvent/TestHelper/NetEvent.TestHelper.csproj +++ b/NetEvent/TestHelper/NetEvent.TestHelper.csproj @@ -8,6 +8,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/docker/start-container b/docker/start-container index 1a39ef4f..c4145477 100644 --- a/docker/start-container +++ b/docker/start-container @@ -3,7 +3,6 @@ if [[ "$DBProvider" = "psql" ]] then export DBConnection="Host=$DBServer;Port=$DBPort;Username=$DBUser;Password=$DBPassword;Database=$DBName" - echo "DBConnection string: $DBConnection" # Database Wait check echo "---------------" echo "WAITING FOR $DBServer:$DBPort..." @@ -12,6 +11,5 @@ fi if [[ "$DBProvider" = "sqlite" ]] then export DBConnection="Data Source=$DBName" - echo "DBConnection string: $DBConnection" /NetEvent/NetEvent.Server fi \ No newline at end of file