diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 6423c5a84..4bff5fe46 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -17,14 +17,5 @@ jobs:
with:
dotnet-version: 10.0.x
- - name: Setup NodeJS
- uses: actions/setup-node@v4
-
- - name: Restore TypeScript dependencies
- run: |
- cd src/MasterData.Web
- npm install
- cd ../../..
-
- name: Build
run: dotnet build
diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml
index 2a10e6980..7a474f2bf 100644
--- a/.github/workflows/nuget.yml
+++ b/.github/workflows/nuget.yml
@@ -14,9 +14,6 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
-
- - name: Setup NodeJS
- uses: actions/setup-node@v4
- name: Restore NuGet packages
run: |
@@ -28,6 +25,7 @@ jobs:
strategy:
matrix:
project:
+ - src/MasterData.Storage.Abstractions
- src/MasterData.Commons
- src/MasterData.Core
- src/MasterData.Web
@@ -40,15 +38,15 @@ jobs:
- uses: actions/checkout@v4
- name: Build and publish NuGet package
run: |
- npm install --prefix src/MasterData.Web
cd ${{ matrix.project }}
- BASE_VERSION=$(dotnet msbuild -nologo -getProperty:Version | tail -n 1 | tr -d '\r')
+ BASE_VERSION=$(dotnet msbuild -nologo -getProperty:VersionPrefix | tail -n 1 | tr -d '\r')
+ PREVIEW_SUFFIX=$(dotnet msbuild -nologo -getProperty:PreviewVersionSuffix | tail -n 1 | tr -d '\r')
if [ "${GITHUB_REF_NAME}" = "rc" ]; then
- PACKAGE_VERSION="${BASE_VERSION}-preview"
+ PACKAGE_VERSION="${BASE_VERSION}-${PREVIEW_SUFFIX}"
else
PACKAGE_VERSION="${BASE_VERSION}"
fi
- dotnet build -c release -p:PackageVersion="${PACKAGE_VERSION}"
- dotnet pack -c release --no-build --output="nuget" -p:PackageVersion="${PACKAGE_VERSION}"
+ dotnet build -c release -p:Version="${PACKAGE_VERSION}" -p:PackageVersion="${PACKAGE_VERSION}" -p:InformationalVersion="${PACKAGE_VERSION}"
+ dotnet pack -c release --no-build --output="nuget" -p:Version="${PACKAGE_VERSION}" -p:PackageVersion="${PACKAGE_VERSION}" -p:InformationalVersion="${PACKAGE_VERSION}"
cd nuget
dotnet nuget push "*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
diff --git a/AGENTS.md b/AGENTS.md
index 7904661c7..066df9282 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -14,9 +14,6 @@ JJMasterData is a .NET library and web UI for generating dynamic CRUDs from data
## Build
- Install .NET SDK
-- Install Node.js for `MasterData.Web` assets.
-- Restore web assets:
- - `npm install --prefix src/MasterData.Web`
- Build from repo root:
- `dotnet build`
diff --git a/Directory.Build.props b/Directory.Build.props
index 489e7f59c..4c5f5a4cd 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -3,10 +3,15 @@
https://www.github.com/JJConsulting/JJMasterData
https://www.github.com/JJConsulting/JJMasterData
JJMasterData.png
- 4.5.37
+ 5.0.0
+ 8
+ rc.$(PreviewNumber)
+ $(VersionPrefix)
+ $(VersionPrefix)-$(VersionSuffix)
$(Version)
- $(Version)
- $(Version)
+ $(VersionPrefix)
+ $(VersionPrefix)
+ $(Version)
README.NuGet.md
true
true
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 9e3d10543..a37cf007f 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,46 +3,48 @@
true
-
+
+
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
-
+
\ No newline at end of file
diff --git a/JJMasterData.slnx b/JJMasterData.slnx
index 5bedf9d82..c2e1acdf0 100644
--- a/JJMasterData.slnx
+++ b/JJMasterData.slnx
@@ -13,7 +13,6 @@
-
diff --git a/README.md b/README.md
index 8a432dca6..52a570531 100644
--- a/README.md
+++ b/README.md
@@ -50,15 +50,14 @@ https://github.com/JJConsulting/JJMasterData/assets/28662273/9b874c9d-2a2f-4d3b-
```shell
dotnet add package JJMasterData.Web
```
-3. Configure your `IConfiguration` source with a connection string at `JJMasterData:ConnectionString` and a secret key at `JJMasterData:SecretKey`
+3. Configure your `IConfiguration` source with a connection string at `JJMasterData:ConnectionString`
```json
{
"JJMasterData": {
"DataDictionaryTableName": "MasterData",
"ConnectionString": "Server=localhost;Database=JJMasterData;Integrated Security=True;Trust Server Certificate=true",
"ReadProcedurePattern": "{tablename}Get",
- "WriteProcedurePattern": "{tablename}Set",
- "SecretKey": "ExampleSecretKey"
+ "WriteProcedurePattern": "{tablename}Set"
}
}
```
@@ -78,7 +77,6 @@ var app = builder.Build();
//Required middlewares
app.UseStaticFiles();
-app.UseSession(); //Session is very important
app.MapDataDictionary();
app.MapMasterData();
@@ -109,11 +107,7 @@ See all steps in [documentation](https://md.jjconsulting.tech/articles/getting_s
5. Set the `WebEntryPoint` as startup project
-6. At `src/Web` run at your terminal
-```bash
-npm i
-```
-7. Run the project
+6. Run the project
## Special Thanks
#### Code contributors
diff --git a/doc/MasterData.Docs/MasterData.Docs.csproj b/doc/MasterData.Docs/MasterData.Docs.csproj
index bb4645869..3f6fc7fa6 100644
--- a/doc/MasterData.Docs/MasterData.Docs.csproj
+++ b/doc/MasterData.Docs/MasterData.Docs.csproj
@@ -1,7 +1,7 @@
- netstandard2.0
+ net10.0
13
JJMasterData.Documentation
JJMasterData.Documentation
diff --git a/doc/MasterData.Docs/articles/components/data_dictionary/file_component.md b/doc/MasterData.Docs/articles/components/data_dictionary/file_component.md
index bfca998c7..5fbaf3c51 100644
--- a/doc/MasterData.Docs/articles/components/data_dictionary/file_component.md
+++ b/doc/MasterData.Docs/articles/components/data_dictionary/file_component.md
@@ -34,6 +34,3 @@ Clicking on "Manage File" will open a new tab, allowing you to attach the desire
- **Export as Link**: This option will change the name of the attachment within the exported file when exporting through the grid.
- **Allow Pasting Files**: Allows the content of the file to be pasted to perform the import, or just a part of the content. It is not necessary to insert the entire file.
-
-- **Show Upload Outside Modal**: If this option is enabled, there will be no "Manage Files" option, and the import field will be displayed alongside the information after clicking edit.
-
diff --git a/doc/MasterData.Docs/articles/configurations.md b/doc/MasterData.Docs/articles/configurations.md
index b766c5416..e26b30ee6 100644
--- a/doc/MasterData.Docs/articles/configurations.md
+++ b/doc/MasterData.Docs/articles/configurations.md
@@ -5,7 +5,7 @@
There are three ways to configure an application:
-**1)** Add your configuration keys in appsettings.json. On .NET Framework you will need to add `IConfiguration` via `Microsoft.Extensions.Configuration`
+**1)** Add your configuration keys in appsettings.json.
> [!TIP]
> To autocomplete with JJMasterData keys in your text editor, put this URL in the JSON Schema of your IDE.
@@ -70,4 +70,3 @@ You can change any property from:
[Read more](localization.md) about localization.
-
diff --git a/doc/MasterData.Docs/articles/custom_rules.md b/doc/MasterData.Docs/articles/customizations.md
similarity index 92%
rename from doc/MasterData.Docs/articles/custom_rules.md
rename to doc/MasterData.Docs/articles/customizations.md
index 283ca6261..be5026bf9 100644
--- a/doc/MasterData.Docs/articles/custom_rules.md
+++ b/doc/MasterData.Docs/articles/customizations.md
@@ -1,4 +1,6 @@
-# Custom Rules
+# Customizations
+
+If you are looking for declarative validations configured directly in the Data Dictionary UI, see [Rules](rules.md).
There are three ways to customize MasterData
@@ -82,7 +84,6 @@ IF (MyCustomLogic, you can use your @Parameters)
```
> [!WARNING]
-> It is not a best practice write business rules at database, recommended only for simple validations.
+> It is not a best practice write business rules as exceptions at the database, please use [Rules](rules.md).
---
-
diff --git a/doc/MasterData.Docs/articles/errors/connection_string.md b/doc/MasterData.Docs/articles/errors/connection_string.md
index e0aae288a..6110ec9d6 100644
--- a/doc/MasterData.Docs/articles/errors/connection_string.md
+++ b/doc/MasterData.Docs/articles/errors/connection_string.md
@@ -4,7 +4,7 @@
This is probably the first error you can find setting up JJMasterData. You can easily
solve it in different ways.
-## ..NET 8+
+## .NET 10
Add a default connection string to appsettings.json.
```json
{
@@ -14,8 +14,8 @@ Add a default connection string to appsettings.json.
}
```
-## .NET Framework 4.8 and .NET Standard 2.0
-Using any supported .NET version, you can set programmatically your connection string.
+## Programmatic configuration
+You can set your connection string programmatically.
```csharp
builder.Services.AddJJMasterDataCore(new MasterDataCoreOptionsConfiguration()
{
diff --git a/doc/MasterData.Docs/articles/getting_started.md b/doc/MasterData.Docs/articles/getting_started.md
index 262f85dfd..6d9014ccf 100644
--- a/doc/MasterData.Docs/articles/getting_started.md
+++ b/doc/MasterData.Docs/articles/getting_started.md
@@ -1,7 +1,6 @@
# Getting Started
-This tutorial assumes you will use .NET 8+, for .NET Framework 4.8 support,
-check our [documentation](miscellaneous/netframework.md).
+This tutorial assumes you will use .NET 10.
## 1. Install JJMasterData.Web from NuGet

@@ -19,7 +18,6 @@ You can replace the appsettings.json url from [here]((https://raw.githubusercont
{
"AllowedHosts": "*",
"JJMasterData": {
- "SecretKey": "My secret key for cryptography",
"ConnectionString": "data source=localhost,1433;initial catalog=JJMasterData;Integrated Security=True"
}
}
@@ -33,9 +31,6 @@ Add the following lines to your Program.cs
//This line will add JJMasterData required services.
builder.Services.AddJJMasterDataWeb();
-//Required middleware for JJMasterData
-app.UseSession();
-
//Add these lines before specifing default route:
// Admin routes to create CRUDs
diff --git a/doc/MasterData.Docs/articles/miscellaneous/assemblies.md b/doc/MasterData.Docs/articles/miscellaneous/assemblies.md
index a0f6fc177..38a32e339 100644
--- a/doc/MasterData.Docs/articles/miscellaneous/assemblies.md
+++ b/doc/MasterData.Docs/articles/miscellaneous/assemblies.md
@@ -7,21 +7,21 @@ JJMasterData dependency tree can be represented by the following diagram:
## Assemblies
### JJMasterData.Web
-Target Frameworks: ..NET 8
+Target Framework: .NET 10
Razor Class Library with web graphical interfaces to manipulate and render your metadata.
### JJMasterData.WebApi
-Target Framework: ..NET 8
+Target Framework: .NET 10
Restful API to consume your metadata at any front-end.
### JJMasterData.Core
-Target Frameworks: ..NET 8, .NET Standard 2.0 and .NET Framework 4.8
+Target Framework: .NET 10
Library to access your metadata from .NET and/or render it at HTML components.
### JJMasterData.Commons
-Target: .NET Standard 2.0
+Target Framework: .NET 10
-Utilities to all assemblies, like database access, l10n, logging and utils.
\ No newline at end of file
+Utilities to all assemblies, like database access, l10n, logging and utils.
diff --git a/doc/MasterData.Docs/articles/miscellaneous/netframework.md b/doc/MasterData.Docs/articles/miscellaneous/netframework.md
deleted file mode 100644
index 549208783..000000000
--- a/doc/MasterData.Docs/articles/miscellaneous/netframework.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# .NET Framework Support
-
-JJMasterData supports legacy .NET Framework systems, including ASP.NET WebForms and MVC5.
-
-## Differences from ASP.NET Core
-
-- JJMasterData.Web is not supported, we recommend starting a [incremental migration](https://devblogs.microsoft.com/dotnet/incremental-asp-net-to-asp-net-core-migration/)
-and use the DataDictionary Razor Class Library in a external website.
-- At Global.asax, use AddJJMasterDataCore() instead of AddJJMasterDataWeb()
-- You will need to include in your Template.master or _Layout.cshtml, all JJMasterData front-end dependencies, check `_MasterDataScripts` and `_MasterDataStylesheets` source code.
-- You will need a custom DI container like SimpleInjector
-- After these steps, simply instantiate your using or use the Render route in your external ..NET 8 website.
-- You will need to handle your manually
\ No newline at end of file
diff --git a/doc/MasterData.Docs/articles/rules.md b/doc/MasterData.Docs/articles/rules.md
new file mode 100644
index 000000000..1164e4fe2
--- /dev/null
+++ b/doc/MasterData.Docs/articles/rules.md
@@ -0,0 +1,193 @@
+# Rules
+
+Rules allow you to run custom scripts before `insert` and `update` operations in a `FormElement`.
+
+Use them when field-level validations are not enough, and you need to validate combinations of values, check data in the database, or apply custom business rules.
+
+## Where to configure
+
+In the Data Dictionary UI, open your element and go to the `Rules` tab.
+
+Each rule has:
+
+- **Name**: Friendly identification for the rule
+- **Rule Type**: Script language used by the rule
+- **Script**: The validation logic itself
+
+Currently supported languages:
+
+- `SQL`
+- `JavaScript`
+
+## How errors work
+
+Rules must produce validation errors only when something is wrong.
+
+If a rule does not produce any error, the operation continues normally.
+
+## SQL rules
+
+SQL rules execute a query and interpret the returned rows as validation errors.
+
+### Result contract
+
+- Return **no rows**: validation succeeded
+- Return **1 column**: general validation error
+- Return **2 columns**: field error, where:
+ - first column = field name
+ - second column = error message
+- Column names do not matter
+
+### Available parameters
+
+You can use form values as parameters with the syntax:
+
+```sql
+{FieldName}
+```
+
+### SQL examples
+
+General error:
+
+```sql
+if exists (
+ select 1
+ from Customer
+ where Document = {Document}
+ and Id <> isnull({Id}, 0)
+)
+ select 'There is already another customer with this document.'
+```
+
+Field error:
+
+```sql
+if exists (
+ select 1
+ from Customer
+ where Email = {Email}
+ and Id <> isnull({Id}, 0)
+)
+ select 'Email', 'This email is already in use.'
+```
+
+Multiple errors:
+
+```sql
+-- Validation: required
+IF @Nome IS NULL OR LTRIM(RTRIM(@Nome)) = ''
+BEGIN
+ SELECT 'Name', 'Name is required';
+END;
+
+-- Validation: minimum and maximum length
+IF LEN(@Nome) < 2 OR LEN(@Nome) > 100
+BEGIN
+ SELECT 'Name must be between 2 and 100 characters';
+END;
+
+-- Validation: only letters and spaces (no numbers or special characters)
+IF @Nome LIKE '%[^A-Za-zÀ-ÿ ]%'
+BEGIN
+ SELECT 'Name', 'Name contains invalid characters';
+END;
+
+-- Validation: avoid multiple consecutive spaces
+IF @Nome LIKE '% %'
+BEGIN
+ SELECT 'Name', 'Name cannot contain consecutive spaces';
+END;
+
+-- Validation: blacklist (business rule example)
+IF UPPER(@Nome) IN ('ADMIN', 'ROOT', 'SYSTEM')
+BEGIN
+ SELECT 'Name', 'Name not allowed';
+END;
+
+-- Validation: avoid unrealistically short names
+IF LEN(REPLACE(@Nome, ' ', '')) < 2
+BEGIN
+ SELECT 'Name', 'Invalid name';
+END;
+
+-- Specific validation (example business rule)
+IF @Nome = 'Bola'
+BEGIN
+ SELECT 'Name', 'Name blocked by internal rule';
+END;
+
+```
+
+## JavaScript rules
+
+JavaScript rules run with [Jint](https://github.com/sebastienros/jint).
+They are executed **server-side**, not in the browser.
+
+The script receives:
+
+- `values`: object containing form values
+- `addError(message)`: adds a general error
+- `addError(name, message)`: adds a field error
+
+### JavaScript examples
+
+General error:
+
+```javascript
+if (!values.Name && !values.CompanyName) {
+ addError("Either Name or CompanyName must be filled.");
+}
+```
+
+Field error:
+
+```javascript
+if (!values.Email) {
+ addError("Email", "Email is required.");
+}
+```
+
+Multiple errors:
+
+```javascript
+if (!values.StartDate) {
+ addError("StartDate", "Start date is required.");
+}
+
+if (!values.EndDate) {
+ addError("EndDate", "End date is required.");
+}
+
+if (values.StartDate && values.EndDate && values.StartDate > values.EndDate) {
+ addError("EndDate", "End date must be greater than or equal to start date.");
+}
+```
+
+Cross-field validation:
+
+```javascript
+if (values.Type === "Company" && !values.Document) {
+ addError("Document", "Document is required for companies.");
+}
+```
+
+## Choosing between SQL and JavaScript
+
+Use `SQL` when:
+
+- validation depends on database queries
+- you want to reuse database-side logic
+- you need to validate against existing persisted data
+
+Use `JavaScript` when:
+
+- validation depends only on current form values
+- you want simpler cross-field logic
+- you want a more expressive scripting syntax for conditional rules
+
+## Notes
+
+- Rule field names must match the dictionary field names when you add field errors
+- General errors are shown as form-level validation messages
+- Field errors are attached to the corresponding field when possible
diff --git a/doc/MasterData.Docs/articles/toc.yml b/doc/MasterData.Docs/articles/toc.yml
index b362b253f..b7c709240 100644
--- a/doc/MasterData.Docs/articles/toc.yml
+++ b/doc/MasterData.Docs/articles/toc.yml
@@ -48,8 +48,10 @@
href: actions/cancel_action.md
- name: Back
href: actions/back_action.md
- - name: Custom Rules
- href: custom_rules.md
+ - name: Customizations
+ href: customizations.md
+ - name: Rules
+ href: rules.md
- name: TagHelpers
href: taghelpers.md
- name: Localization
@@ -146,7 +148,5 @@
items:
- name: Multiple Forms Support
href: multiple_forms.md
- - name: .NET Framework Support
- href: miscellaneous/netframework.md
- name: Assemblies
href: miscellaneous/assemblies.md
diff --git a/doc/MasterData.Docs/articles/tutorials/creating_data_dictionary.md b/doc/MasterData.Docs/articles/tutorials/creating_data_dictionary.md
index 628dbf936..09291753d 100644
--- a/doc/MasterData.Docs/articles/tutorials/creating_data_dictionary.md
+++ b/doc/MasterData.Docs/articles/tutorials/creating_data_dictionary.md
@@ -108,9 +108,6 @@ With Alignment At Grid at Right:
#### Export
You can define whether or not the field will be exported.
-#### Validade Request
-On .NET Framework 4.8 systems, the field will validate dangerous values, like Html tags and SQL commands.
-
## **Panels**
Allows you to separate the dictionary fields into panels.
But only for add, edit and view actions.
@@ -149,6 +146,14 @@ The Actions field is divided into two, Grid and Toolbar.
- Filter: Shows all filter options for searching items within the table.
- Log: Records and displays the actions performed within the table, including adding, editing and deleting.
+## Rules
+Within the Rules tab you can create script-based validations executed before `insert` and `update`.
+
+- SQL rules can return rows representing validation errors
+- JavaScript rules can call `addError(message)` or `addError(fieldName, message)`
+
+For the complete reference, see [Rules](../rules.md).
+
## **API**
Within this tab it will be possible to edit each verb responsible for http permissions within the REST API.
- ApplyUseridOn: Name of the field where the user ID filter will be applied.
diff --git a/doc/MasterData.Docs/articles/tutorials/data_file.md b/doc/MasterData.Docs/articles/tutorials/data_file.md
index 5bcfe697e..86b081f16 100644
--- a/doc/MasterData.Docs/articles/tutorials/data_file.md
+++ b/doc/MasterData.Docs/articles/tutorials/data_file.md
@@ -51,7 +51,7 @@ Where we configure the maximum size in bytes allowed in the upload. The maximum
### What can you do
If you want to increase the size of this field, you will need to change the setting **MaxRequestLength**
-The default size is 4 MB for .NET Framework and 30MB for .NET Core.
+The default size is 30 MB for ASP.NET Core.
## Why when enabling a MultipleFile property I cannot enable ExportAsLink?
@@ -66,4 +66,4 @@ Unfortunately in this scenario you will have to create a field for each file.
## Como acessar o arquivo de fora do elemento em uma rota externa?
-Utilize o endpoint `/MasterData/File/Index/{elementName}/{fieldName}/{id}?fileName=YourFileName.png` para recuperar seu arquivo. Onde {id} é sua chave primária, caso seja mais de um campo, utilize vírgula para separar os valores.
\ No newline at end of file
+Utilize o endpoint `/MasterData/File/Index/{elementName}/{fieldName}/{id}?fileName=YourFileName.png` para recuperar seu arquivo. Onde {id} é sua chave primária, caso seja mais de um campo, utilize vírgula para separar os valores.
diff --git a/doc/MasterData.Docs/articles/tutorials/ui_options.md b/doc/MasterData.Docs/articles/tutorials/ui_options.md
index bfa8417da..7f6071d28 100644
--- a/doc/MasterData.Docs/articles/tutorials/ui_options.md
+++ b/doc/MasterData.Docs/articles/tutorials/ui_options.md
@@ -41,7 +41,7 @@ When displaying multiple items from your table, you can keep their titles fixed

### **MaintainValuesOnLoad**
-This option will ensure that your search through the filter is saved when reloading the page, whether searching for filters or configuration options.
+This option will ensure that your search through the filter is saved in cookies when reloading the page, whether searching for filters or configuration options.

diff --git a/doc/MasterData.Docs/themes/jjconsulting/public/main.css b/doc/MasterData.Docs/themes/jjconsulting/public/main.css
index c8ce11d79..67dda0ac5 100644
--- a/doc/MasterData.Docs/themes/jjconsulting/public/main.css
+++ b/doc/MasterData.Docs/themes/jjconsulting/public/main.css
@@ -108,7 +108,7 @@ header {
main.container-xxl,
footer .container-xxl,
.search-results.container-xxl {
- max-width: 1500px;
+ max-width: 1800px;
padding-left: 0.8rem;
padding-right: 0.8rem;
}
diff --git a/doc/README.md b/doc/README.md
index 5a6b431ff..fa59e1a22 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -3,7 +3,7 @@ We use docfx to build the documentation in markdown to learn more visit
[DocFx Documetantion](https://dotnet.github.io/docfx/)
## Building from source
-1. Install [.NET Framework 4.8]
+1. Install [.NET 10 SDK](https://dotnet.microsoft.com/download)
2. Install [NodeJS](https://nodejs.org/en/download/)
diff --git a/example/MasterData.WebEntryPoint/Program.cs b/example/MasterData.WebEntryPoint/Program.cs
index 85f0227c9..b6b96eca2 100644
--- a/example/MasterData.WebEntryPoint/Program.cs
+++ b/example/MasterData.WebEntryPoint/Program.cs
@@ -50,7 +50,6 @@
}
app.UseStaticFiles();
-app.UseSession();
app.UseHttpsRedirection();
app.UseRouting();
app.UseResponseCaching();
diff --git a/jjmasterdata.json b/jjmasterdata.json
index f2c6f6210..ada4a96f7 100644
--- a/jjmasterdata.json
+++ b/jjmasterdata.json
@@ -23,9 +23,6 @@
"null"
]
},
- "SupportNetFramework": {
- "type": "boolean"
- },
"EnableBundleAndMinification": {
"type": "boolean"
},
@@ -53,12 +50,6 @@
"null"
]
},
- "MasterDataUrl": {
- "type": [
- "string",
- "null"
- ]
- },
"ExportationFolderPath": {
"type": [
"string",
@@ -99,32 +90,23 @@
"string",
"null"
]
- },
- "SecretKey": {
- "type": [
- "string",
- "null"
- ]
}
},
"required": [
"LayoutPath",
"ModalLayoutPath",
"CustomBootstrapPath",
- "SupportNetFramework",
"EnableBundleAndMinification",
"CustomScriptsPaths",
"DataDictionaryTableName",
"AuditLogTableName",
- "MasterDataUrl",
"ExportationFolderPath",
"ConnectionString",
"ConnectionProvider",
"LocalizationTableName",
"ReadProcedurePattern",
- "WriteProcedurePattern",
- "SecretKey"
+ "WriteProcedurePattern"
]
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ConsoleApps/MasterData.CommandLine/Hosting/ConsoleRunner.cs b/src/ConsoleApps/MasterData.CommandLine/Hosting/ConsoleRunner.cs
index 400442d73..5af15077d 100644
--- a/src/ConsoleApps/MasterData.CommandLine/Hosting/ConsoleRunner.cs
+++ b/src/ConsoleApps/MasterData.CommandLine/Hosting/ConsoleRunner.cs
@@ -9,8 +9,6 @@ namespace JJMasterData.CommandLine.Hosting;
public sealed class ConsoleRunner(IAnsiConsole console)
{
- private const string SecretKey = "jjmasterdata-console-tool";
-
public Task ImportAsync(MasterDataCommandSettings settings, CancellationToken cancellationToken)
{
return ExecuteAsync(
@@ -68,7 +66,6 @@ private static IConfiguration BuildConfiguration(MasterDataCommandSettings setti
{
["JJMasterData:ConnectionString"] = settings.Connection,
["JJMasterData:ConnectionProvider"] = nameof(DataAccessProvider.SqlServer),
- ["JJMasterData:SecretKey"] = SecretKey,
["JJMasterData:DataDictionaryTableSchema"] = schema,
["JJMasterData:DataDictionaryTableName"] = table
};
@@ -89,4 +86,4 @@ private static (string Schema, string Table) ParseTable(string? table)
? (parts[0], parts[1])
: ("dbo", parts[0]);
}
-}
\ No newline at end of file
+}
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/ExpressionsMigrationService.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/ExpressionsMigrationService.cs
deleted file mode 100644
index e9408003f..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/ExpressionsMigrationService.cs
+++ /dev/null
@@ -1,166 +0,0 @@
-using JJMasterData.Commons.Util;
-using JJMasterData.Core.DataDictionary.Models;
-using JJMasterData.Core.DataDictionary.Models.Actions;
-using JJMasterData.Core.DataDictionary.Repository.Abstractions;
-
-namespace JJMasterData.LegacyMetadataMigrator;
-
-public class ExpressionsMigrationService(
- IDataDictionaryRepository dataDictionaryRepository)
-{
- private IDataDictionaryRepository DataDictionaryRepository { get; } = dataDictionaryRepository;
-
- public void Migrate()
- {
- var start = DateTime.Now;
-
- var formElements = DataDictionaryRepository.GetFormElementListAsync().GetAwaiter().GetResult();
-
- foreach (var formElement in formElements)
- {
- foreach (var field in formElement.Fields)
- {
- FixFieldExpressions(field);
- }
-
- foreach (var panel in formElement.Panels)
- {
- FixPanelExpressions(panel);
- }
-
- foreach (var action in formElement.Options.GridTableActions)
- {
- FixActionExpressions(action);
- }
-
- foreach (var action in formElement.Options.GridToolbarActions)
- {
- FixActionExpressions(action);
- }
-
- foreach (var action in formElement.Options.FormToolbarActions)
- {
- FixActionExpressions(action);
- }
-
- DataDictionaryRepository.InsertOrReplace(formElement);
- }
-
- Console.WriteLine("Process started: {0}", start);
- Console.WriteLine("Process finished: {0}", DateTime.Now);
- }
-
- private void FixFieldExpressions(FormElementField field)
- {
- var visibleExpressionBefore = field.VisibleExpression;
-
- field.VisibleExpression = FixQuotationMarks(visibleExpressionBefore);
-
- if (visibleExpressionBefore != field.VisibleExpression)
- {
- Console.WriteLine("{0} VisibleExpression Before: {1}", field.Name,
- visibleExpressionBefore);
- Console.WriteLine("{0} VisibleExpression After: {1}", field.Name,
- field.VisibleExpression);
- }
-
- var enableExpressionBefore = field.EnableExpression;
-
- field.EnableExpression = FixQuotationMarks(enableExpressionBefore);
-
- if (enableExpressionBefore != field.EnableExpression)
- {
- Console.WriteLine("{0} EnableExpression Before: {1}", field.Name,
- enableExpressionBefore);
- Console.WriteLine("{0} EnableExpression After: {1}", field.Name, field.EnableExpression);
- }
-
- foreach (var action in field.Actions)
- {
- FixActionExpressions(action);
- }
- }
-
- // ReSharper disable once MemberCanBeMadeStatic.Local
-#pragma warning disable CA1822
- private void FixPanelExpressions(FormElementPanel panel)
-#pragma warning restore CA1822
- {
- var visibleExpressionBefore = panel.VisibleExpression;
-
- panel.VisibleExpression = FixQuotationMarks(visibleExpressionBefore);
-
- if (visibleExpressionBefore != panel.VisibleExpression)
- {
- Console.WriteLine("Panel {0} VisibleExpression Before: {1}", panel.PanelId,
- visibleExpressionBefore);
- Console.WriteLine("Panel {0} VisibleExpression After: {1}", panel.PanelId,
- panel.VisibleExpression);
- }
-
- var enableExpressionBefore = panel.EnableExpression;
-
- panel.EnableExpression = FixQuotationMarks(enableExpressionBefore);
-
- if (enableExpressionBefore != panel.EnableExpression)
- {
- Console.WriteLine("Panel {0} EnableExpression Before: {1}", panel.PanelId,
- enableExpressionBefore);
- Console.WriteLine("Panel {0} EnableExpression After: {1}", panel.PanelId,
- panel.EnableExpression);
- }
- }
-
- // ReSharper disable once MemberCanBeMadeStatic.Local
-#pragma warning disable CA1822
- private void FixActionExpressions(BasicAction action)
-#pragma warning restore CA1822
- {
- var visibleExpressionBefore = action.VisibleExpression;
-
- action.VisibleExpression = FixQuotationMarks(visibleExpressionBefore);
-
- if (visibleExpressionBefore != action.VisibleExpression)
- {
- Console.WriteLine("Action {0} VisibleExpression Before: {1}", action.Name,
- visibleExpressionBefore);
- Console.WriteLine("Action {0} VisibleExpression After: {1}", action.Name,
- action.VisibleExpression);
- }
-
- var enableExpressionBefore = action.EnableExpression;
-
- action.EnableExpression = FixQuotationMarks(enableExpressionBefore);
-
- if (enableExpressionBefore != action.EnableExpression)
- {
- Console.WriteLine("Action {0} EnableExpression Before: {1}", action.Name,
- enableExpressionBefore);
- Console.WriteLine("Action {0} EnableExpression After: {1}", action.Name,
- action.EnableExpression);
- }
- }
-
- private static string FixQuotationMarks(string? expression)
- {
- if (string.IsNullOrEmpty(expression))
- return "val:1";
-
- var quotedValues = StringManager.FindValuesByInterval(expression, '\'','\'').ToList();
- var bracedValues = StringManager.FindValuesByInterval(expression, '{','}').ToList();
-
- var newExpression = expression;
-
- foreach (var bracedValue in bracedValues)
- {
- var hasQuotes = quotedValues.Any(quotedValue => quotedValue.Contains(bracedValue));
-
- if(hasQuotes)
- continue;
-
- newExpression = expression.Replace($"{{{bracedValue}}}", $"'{{{bracedValue}}}'");
- }
-
- return newExpression;
- }
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/GridActions.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/GridActions.cs
deleted file mode 100644
index c59da8d9a..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/GridActions.cs
+++ /dev/null
@@ -1,260 +0,0 @@
-#nullable disable
-
-using JJMasterData.Core.DataDictionary.Models.Actions;
-using Newtonsoft.Json;
-
-namespace JJMasterData.LegacyMetadataMigrator.FormElementMigration;
-
-
-public class GridActions
-{
- [JsonProperty("editAction")]
- public EditAction EditAction { get; set; } = new();
-
- [JsonProperty("deleteAction")]
- public DeleteAction DeleteAction { get; set; } = new();
-
- [JsonProperty("viewAction")]
- public ViewAction ViewAction { get; set; } = new();
-
- [JsonProperty("commandActions")]
- private List CommandActions { get; set; } = [];
-
- [JsonProperty("urlRedirectActions")]
- private List UrlRedirectActions { get; set; } = [];
-
- [JsonProperty("internalActions")]
- private List InternalActions { get; set; } = [];
-
- [JsonProperty("jsActions")]
- private List JsActions { get; set; } = [];
-
-
- public void Set(BasicAction action)
- {
- if (action is ViewAction viewAction)
- {
- ViewAction = viewAction;
- }
- else if (action is EditAction editAction)
- {
- EditAction = editAction;
- }
- else if (action is DeleteAction deleteAction)
- {
- DeleteAction = deleteAction;
- }
- else if (action is SqlCommandAction cmdAction)
- {
- for (int i = 0; i < CommandActions.Count; i++)
- {
- if (CommandActions[i].Name.Equals(action.Name))
- {
- CommandActions[i] = cmdAction;
- return;
- }
- }
- CommandActions.Add(cmdAction);
- }
- else if (action is UrlRedirectAction urlAction)
- {
- for(int i =0;i< UrlRedirectActions.Count; i++)
- {
- if (UrlRedirectActions[i].Name.Equals(action.Name))
- {
- UrlRedirectActions[i] = urlAction;
- return;
- }
- }
- UrlRedirectActions.Add(urlAction);
- }
- else if (action is InternalAction internalAction)
- {
- for (int i = 0; i < InternalActions.Count; i++)
- {
- if (InternalActions[i].Name.Equals(action.Name))
- {
- InternalActions[i] = internalAction;
- return;
- }
- }
- InternalActions.Add(internalAction);
- }
- else if (action is ScriptAction jsAction)
- {
- for (int i = 0; i < JsActions.Count; i++)
- {
- if (JsActions[i].Name.Equals(action.Name))
- {
- JsActions[i] = jsAction;
- return;
- }
- }
- JsActions.Add(jsAction);
- }
- else
- {
- throw new ArgumentException("Invalid Action");
- }
- }
-
- public void Add(SqlCommandAction action)
- {
- ValidateAction(action);
- CommandActions.Add(action);
- }
-
-
- public void Add(UrlRedirectAction action)
- {
- ValidateAction(action);
- UrlRedirectActions.Add(action);
- }
-
- public void Add(InternalAction action)
- {
- ValidateAction(action);
- InternalActions.Add(action);
- }
-
- public void Add(ScriptAction action)
- {
- ValidateAction(action);
- JsActions.Add(action);
- }
-
- public void Remove(SqlCommandAction action)
- {
- ValidateAction(action);
- CommandActions.Remove(action);
- }
- public void Remove(UrlRedirectAction action)
- {
- ValidateAction(action);
- UrlRedirectActions.Remove(action);
- }
-
- public void Remove(InternalAction action)
- {
- ValidateAction(action);
- InternalActions.Remove(action);
- }
-
- public void Remove(ScriptAction action)
- {
- ValidateAction(action);
- JsActions.Remove(action);
- }
-
-
- public void Remove(BasicAction action)
- {
- if (action is SqlCommandAction acSql)
- {
- Remove(acSql);
- }
- else if (action is UrlRedirectAction acUrl)
- {
- Remove(acUrl);
- }
- else if (action is InternalAction acInternal)
- {
- Remove(acInternal);
- }
- else if (action is ScriptAction acJs)
- {
- Remove(acJs);
- }
- else
- {
- throw new ArgumentException("Invalid Action");
- }
- }
-
- public void Remove(string actionName)
- {
- BasicAction action = Get(actionName);
- Remove(action);
- }
-
-#pragma warning disable CA1822
- // ReSharper disable once MemberCanBeMadeStatic.Local
- private void ValidateAction(BasicAction action)
-#pragma warning restore CA1822
- {
- if (action == null)
- throw new ArgumentNullException(nameof(action));
-
- if (string.IsNullOrEmpty(action.Name))
- throw new ArgumentException("Property name action is not valid");
- }
-
- public BasicAction Get(string name)
- {
- BasicAction action = null;
- if (ViewAction.Name.Equals(name))
- return ViewAction;
-
- if (EditAction.Name.Equals(name))
- return EditAction;
-
- if (DeleteAction.Name.Equals(name))
- return DeleteAction;
-
- action = CommandActions.Find(x => x.Name.Equals(name));
- if (action != null)
- return action;
-
- action = UrlRedirectActions.Find(x => x.Name.Equals(name));
- if (action != null)
- return action;
-
- action = InternalActions.Find(x => x.Name.Equals(name));
- if (action != null)
- return action;
-
- action = JsActions.Find(x => x.Name.Equals(name));
- if (action != null)
- return action;
-
- return null;
- }
-
- public void SetDefault(string actionName)
- {
- foreach (var action in GetAll())
- {
- action.IsDefaultOption = action.Name.Equals(actionName);
- }
- }
-
- public List GetAll()
- {
- var listAction = new List();
-
- if (ViewAction is not null)
- listAction.Add(ViewAction);
-
- if (EditAction is not null)
- listAction.Add(EditAction);
-
- if (DeleteAction is not null)
- listAction.Add(DeleteAction);
-
- if (CommandActions is { Count: > 0 })
- listAction.AddRange(CommandActions.ToArray());
-
- if (UrlRedirectActions is { Count: > 0 })
- listAction.AddRange(UrlRedirectActions.ToArray());
-
- if (InternalActions is { Count: > 0 })
- listAction.AddRange(InternalActions.ToArray());
-
- if (JsActions is { Count: > 0 })
- listAction.AddRange(JsActions.ToArray());
-
- return listAction.OrderBy(x => x.Order).ToList();
- }
-
- public int Count => GetAll().FindAll(x => x.IsVisible).Count;
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/GridToolbarActions.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/GridToolbarActions.cs
deleted file mode 100644
index 7fe8cd2f9..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/GridToolbarActions.cs
+++ /dev/null
@@ -1,311 +0,0 @@
-#nullable disable
-
-using JJMasterData.Core.DataDictionary.Models.Actions;
-using Newtonsoft.Json;
-
-namespace JJMasterData.LegacyMetadataMigrator.FormElementMigration;
-
-public class GridToolbarActions
-{
- [JsonProperty("insertAction")]
- public InsertAction InsertAction { get; set; } = new();
-
- [JsonProperty("legendAction")]
- public LegendAction LegendAction { get; set; } = new();
-
- [JsonProperty("refreshAction")]
- public RefreshAction RefreshAction { get; set; } = new();
-
- [JsonProperty("filterAction")]
- public FilterAction FilterAction { get; set; } = new();
-
- [JsonProperty("importAction")]
- public ImportAction ImportAction { get; set; } = new();
-
- [JsonProperty("exportAction")]
- public ExportAction ExportAction { get; set; } = new();
-
- [JsonProperty("configAction")]
- public ConfigAction ConfigAction { get; set; } = new();
-
- [JsonProperty("sortAction")]
- public SortAction SortAction { get; set; } = new();
-
- [JsonProperty("logAction")]
- public AuditLogGridToolbarAction AuditLogGridToolbarAction { get; set; } = new();
-
- [JsonProperty("commandActions")]
- private List CommandActions { get; set; } = [];
-
- [JsonProperty("urlRedirectActions")]
- private List UrlRedirectActions { get; set; } = [];
-
- [JsonProperty("internalActions")]
- private List InternalActions { get; set; } = [];
-
- [JsonProperty("jsActions")]
- private List JsActions { get; set; } = [];
-
-
- public void Set(BasicAction action)
- {
- switch (action)
- {
- case InsertAction insertAction:
- InsertAction = insertAction;
- break;
- case LegendAction legendAction:
- LegendAction = legendAction;
- break;
- case RefreshAction refreshAction:
- RefreshAction = refreshAction;
- break;
- case FilterAction filterAction:
- FilterAction = filterAction;
- break;
- case ImportAction importAction:
- ImportAction = importAction;
- break;
- case ExportAction exportAction:
- ExportAction = exportAction;
- break;
- case ConfigAction configAction:
- ConfigAction = configAction;
- break;
- case SortAction sortAction:
- SortAction = sortAction;
- break;
- case AuditLogGridToolbarAction logAction:
- AuditLogGridToolbarAction = logAction;
- break;
- case SqlCommandAction cmdAction:
- {
- for (int i = 0; i < CommandActions.Count; i++)
- {
- if (CommandActions[i].Name.Equals(action.Name))
- {
- CommandActions[i] = cmdAction;
- return;
- }
- }
- CommandActions.Add(cmdAction);
- break;
- }
- case UrlRedirectAction urlAction:
- {
- for (int i = 0; i < UrlRedirectActions.Count; i++)
- {
- if (UrlRedirectActions[i].Name.Equals(action.Name))
- {
- UrlRedirectActions[i] = urlAction;
- return;
- }
- }
- UrlRedirectActions.Add(urlAction);
- break;
- }
- case InternalAction internalAction:
- {
- for (int i = 0; i < InternalActions.Count; i++)
- {
- if (InternalActions[i].Name.Equals(action.Name))
- {
- InternalActions[i] = internalAction;
- return;
- }
- }
- InternalActions.Add(internalAction);
- break;
- }
- case ScriptAction scriptAction:
- {
- for (int i = 0; i < JsActions.Count; i++)
- {
- if (JsActions[i].Name.Equals(action.Name))
- {
- JsActions[i] = scriptAction;
- return;
- }
- }
- JsActions.Add(scriptAction);
- break;
- }
- default:
- throw new ArgumentException("Invalid Action");
- }
- }
-
-
- public void Add(SqlCommandAction action)
- {
- ValidateAction(action);
- CommandActions.Add(action);
- }
-
- public void Add(UrlRedirectAction action)
- {
- ValidateAction(action);
- UrlRedirectActions.Add(action);
- }
-
- public void Add(InternalAction action)
- {
- ValidateAction(action);
- InternalActions.Add(action);
- }
-
- public void Add(ScriptAction action)
- {
- ValidateAction(action);
- JsActions.Add(action);
- }
-
- public void Add(BasicAction action)
- {
- if (action is SqlCommandAction cmdAction)
- Add(cmdAction);
- else if (action is UrlRedirectAction urlAction)
- Add(urlAction);
- else if (action is InternalAction internalAction)
- Add(internalAction);
- else if (action is ScriptAction scriptAction)
- Add(scriptAction);
- else
- throw new ArgumentException("Invalid Action");
- }
-
- public void Remove(SqlCommandAction action)
- {
- ValidateAction(action);
- CommandActions.Remove(action);
- }
- public void Remove(UrlRedirectAction action)
- {
- ValidateAction(action);
- UrlRedirectActions.Remove(action);
- }
-
- public void Remove(InternalAction action)
- {
- ValidateAction(action);
- InternalActions.Remove(action);
- }
- public void Remove(ScriptAction action)
- {
- ValidateAction(action);
- JsActions.Remove(action);
- }
-
- public void Remove(BasicAction action)
- {
- if (action is SqlCommandAction acSql)
- {
- Remove(acSql);
- }
- else if (action is UrlRedirectAction acUrl)
- {
- Remove(acUrl);
- }
- else if (action is InternalAction acInternal)
- {
- Remove(acInternal);
- }
- else if (action is ScriptAction jScriptAction)
- {
- Remove(jScriptAction);
- }
- else
- {
- throw new ArgumentException("Invalid Action");
- }
- }
-
- public void Remove(string actionName)
- {
- BasicAction action = Get(actionName);
- Remove(action);
- }
-
-#pragma warning disable CA1822
- // ReSharper disable once MemberCanBeMadeStatic.Local
- private void ValidateAction(BasicAction action)
-#pragma warning restore CA1822
- {
- if (action == null)
- throw new ArgumentNullException(nameof(action));
-
- if (string.IsNullOrEmpty(action.Name))
- throw new ArgumentException("Property name action is not valid");
- }
-
- public BasicAction Get(string name)
- {
- return GetAll().Find(x => x.Name.Equals(name));
- }
-
-
- public List GetAll()
- {
- var actionList = new List();
-
- if (InsertAction is not null)
- {
- }
- else
- {
- InsertAction = new InsertAction();
- }
-
- actionList.Add(InsertAction);
-
- if (LegendAction is not null)
- {
- }
- else
- {
- LegendAction = new LegendAction();
- }
-
- actionList.Add(LegendAction);
-
- RefreshAction ??= new RefreshAction();
-
- actionList.Add(RefreshAction);
-
- FilterAction ??= new FilterAction();
-
- actionList.Add(FilterAction);
-
- ImportAction ??= new ImportAction();
-
- actionList.Add(ImportAction);
-
- ExportAction ??= new ExportAction();
-
- actionList.Add(ExportAction);
-
- ConfigAction ??= new ConfigAction();
-
- actionList.Add(ConfigAction);
-
- SortAction ??= new SortAction();
-
- actionList.Add(SortAction);
-
- AuditLogGridToolbarAction ??= new AuditLogGridToolbarAction();
-
- actionList.Add(AuditLogGridToolbarAction);
- if (CommandActions is { Count: > 0 })
- actionList.AddRange(CommandActions.ToArray());
-
- if (UrlRedirectActions is { Count: > 0 })
- actionList.AddRange(UrlRedirectActions.ToArray());
-
- if (InternalActions is { Count: > 0 })
- actionList.AddRange(InternalActions.ToArray());
-
- if (JsActions is { Count: > 0 })
- actionList.AddRange(JsActions.ToArray());
- return actionList.OrderBy(x => x.Order).ToList();
- }
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/Metadata.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/Metadata.cs
deleted file mode 100644
index 67d0bee45..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/Metadata.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-#nullable disable
-
-using System.Collections;
-using JJMasterData.Commons.Data.Entity.Models;
-using JJMasterData.Core.DataDictionary.Models;
-using Newtonsoft.Json;
-
-namespace JJMasterData.LegacyMetadataMigrator.FormElementMigration;
-
-[JsonObject("elementInfo")]
-public class Metadata
-{
- [JsonProperty("table")]
- public Element Table { get; set; }
-
- [JsonProperty("form")]
- public MetadataForm Form { get; set; }
-
- [JsonProperty("uioptions")]
- public MetadataOptions Options { get; set; }
-
- [JsonProperty("api")]
- public MetadataApiOptions ApiOptions { get; set; }
-
- public static explicit operator FormElement(Metadata metadata) => metadata.GetFormElement();
-
- public FormElement GetFormElement()
- {
- var formElement = new FormElement(Table)
- {
- Title = Form.Title,
- SubTitle = Form.SubTitle,
- Panels = Form.Panels,
- Info = Table.Info,
- Indexes = Table.Indexes,
- EnableSynchronism = Table.EnableSynchronism,
- SynchronismMode = Table.SynchronismMode,
- };
-
- foreach (var item in Form.FormFields)
- {
- var field = formElement.Fields[item.Name];
- field.Component = item.Component;
- field.VisibleExpression = item.VisibleExpression;
- field.EnableExpression = item.EnableExpression;
- field.TriggerExpression = item.TriggerExpression;
- field.LineGroup = item.LineGroup;
- field.CssClass = item.CssClass;
- field.HelpDescription = item.HelpDescription;
- field.DataItem = item.DataItem;
- field.Attributes[FormElementField.MinValueAttribute] = item.MinValue;
- field.Attributes[FormElementField.MaxValueAttribute] = item.MaxValue;
- field.DataFile = item.DataFile;
- field.Export = item.Export;
- field.ValidateRequest = item.ValidateRequest ?? true;
- field.AutoPostBack = item.AutoPostBack;
- field.NumberOfDecimalPlaces = item.NumberOfDecimalPlaces;
- field.Actions = item.Actions;
- field.Attributes = item.Attributes?.Cast()
- .ToDictionary(kvp => kvp.Key.ToString(), kvp => kvp.Value) ?? new Dictionary();
- field.PanelId = item.PanelId;
- field.InternalNotes = item.InternalNotes;
- }
-
-
- formElement.Options = new FormElementOptions
- {
- Form = Options.Form,
- Grid = Options.Grid
- };
-
- formElement.Options.GridTableActions.Clear();
-
- foreach (var a in Options.GridActions.GetAll())
- {
- formElement.Options.GridTableActions.Add(a);
- }
-
- formElement.Options.GridToolbarActions.Clear();
-
- foreach (var a in Options.ToolbarActions.GetAll())
- {
- formElement.Options.GridToolbarActions.Add(a);
- }
-
- formElement.ApiOptions = new FormElementApiOptions
- {
- JsonFormatting = ApiOptions.FormatType,
- EnableAdd = ApiOptions.EnableAdd,
- EnableGetAll = ApiOptions.EnableGetAll,
- EnableDel = ApiOptions.EnableDel,
- EnableUpdate = ApiOptions.EnableUpdate,
- EnableGetDetail = ApiOptions.EnableGetDetail,
- EnableUpdatePart = ApiOptions.EnableUpdatePart,
- ApplyUserIdOn = ApiOptions.ApplyUserIdOn
- };
-
- return formElement;
- }
-
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataApiOptions.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataApiOptions.cs
deleted file mode 100644
index 50ec645c7..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataApiOptions.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-#nullable disable
-
-using System.Runtime.Serialization;
-using JJMasterData.Core.DataDictionary.Models;
-using Newtonsoft.Json;
-
-namespace JJMasterData.LegacyMetadataMigrator.FormElementMigration;
-
-[DataContract]
-public class MetadataApiOptions
-{
- ///
- /// Get all records. Verb GET
- ///
- [JsonProperty("enableGetAll")]
- public bool EnableGetAll { get; set; }
-
- ///
- /// Get a record detail. Verb GET
- ///
- [JsonProperty("enableGetDetail")]
- public bool EnableGetDetail { get; set; }
-
- ///
- /// Add new records. Verb POST
- ///
- [JsonProperty("enableAdd")]
- public bool EnableAdd { get; set; }
-
- ///
- /// Update records. Verb PUT
- ///
- [JsonProperty("enableUpdate")]
- public bool EnableUpdate { get; set; }
-
- ///
- /// Update some especifics fields. Verb PATCH
- ///
- [JsonProperty("enableUpdatePart")]
- public bool EnableUpdatePart { get; set; }
-
- ///
- /// Delete a record. Verb DEL
- ///
- [JsonProperty("enableDel")]
- public bool EnableDel { get; set; }
-
- ///
- /// Json Format
- ///
- [JsonProperty("formatType")]
- public ApiJsonFormatting FormatType { get; set; } = ApiJsonFormatting.Lowercase;
-
- ///
- /// Aways apply UserId (from login) as filter or on set
- ///
- [JsonProperty("applyUserIdOn")]
- public string ApplyUserIdOn { get; set; }
-
-
- ///
- /// Format the field according to the dictionary parameterization
- ///
- public string GetFieldNameParsed(string fieldName)
- {
- return FormatType == ApiJsonFormatting.Lowercase ? fieldName.ToLower() : fieldName;
- }
-
-
- public bool HasSetMehtod()
- {
- return EnableAdd ||
- EnableUpdate ||
- EnableUpdatePart ||
- EnableDel;
- }
-
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataForm.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataForm.cs
deleted file mode 100644
index cb16bca43..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataForm.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-#nullable disable
-
-using System.Runtime.Serialization;
-using JJMasterData.Core.DataDictionary.Models;
-using Newtonsoft.Json;
-
-namespace JJMasterData.LegacyMetadataMigrator.FormElementMigration;
-
-[DataContract]
-public class MetadataForm
-{
- [JsonProperty("formfields")]
- public List FormFields { get; set; } = [];
-
- [JsonProperty("title")]
- public string Title { get; set; }
-
- [JsonProperty("subtitle")]
- public string SubTitle { get; set; }
-
- [JsonProperty("panels")]
- public List Panels { get; set; } = [];
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataFormField.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataFormField.cs
deleted file mode 100644
index 02221833f..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataFormField.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-#nullable disable
-
-using System.Collections;
-using JJMasterData.Core.DataDictionary.Models;
-using JJMasterData.Core.DataDictionary.Models.Actions;
-using Newtonsoft.Json;
-
-namespace JJMasterData.LegacyMetadataMigrator.FormElementMigration;
-
-
-public class MetadataFormField
-{
- [JsonProperty("name")]
- public string Name { get; set; }
-
- [JsonProperty("component")]
- public FormComponent Component { get; set; }
-
- [JsonProperty("visibleexpression")]
- public string VisibleExpression { get; set; }
-
- [JsonProperty("enableexpression")]
- public string EnableExpression { get; set; }
-
- [JsonProperty("triggerexpression")]
- public string TriggerExpression { get; set; }
-
- [JsonProperty("order")]
- public int Order { get; set; }
-
- [JsonProperty("linegroup")]
- public int LineGroup { get; set; }
-
- [JsonProperty("cssclass")]
- public string CssClass { get; set; }
-
- [JsonProperty("helpdescription")]
- public string HelpDescription { get; set; }
-
- [JsonProperty("dataitem")]
- public FormElementDataItem DataItem { get; set; }
-
- [JsonProperty("datafile")]
- public FormElementDataFile DataFile { get; set; }
-
- [JsonProperty("export")]
- public bool Export { get; set; }
-
- [JsonProperty("validaterequest")]
- public bool? ValidateRequest { get; set; }
-
- [JsonProperty("autopostback")]
- public bool AutoPostBack { get; set; }
-
- [JsonProperty("maxvalue")]
- public float? MaxValue { get; set; }
-
- [JsonProperty("minvalue")]
- public float? MinValue { get; set; }
-
- [JsonProperty("numberdecimalplaces")]
- public int NumberOfDecimalPlaces { get; set; }
-
- [JsonProperty("actions")]
- public FormElementFieldActionList Actions { get; set; }
-
- [JsonProperty("attributes")]
- public Hashtable Attributes { get; set; }
-
- [JsonProperty("panelid")]
- public int PanelId { get; set; }
-
- [JsonProperty("internalnotes")]
- public string InternalNotes { get; set; }
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataInfo.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataInfo.cs
deleted file mode 100644
index fa2ca232c..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataInfo.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-#nullable disable
-using Newtonsoft.Json;
-
-namespace JJMasterData.LegacyMetadataMigrator.FormElementMigration;
-
-public class MetadataInfo
-{
- [JsonProperty("name")]
- public string Name { get; set; }
-
- [JsonProperty("tablename")]
- public string TableName { get; set; }
-
- [JsonProperty("info")]
- public string Info { get; set; }
-
- [JsonProperty("sync")]
- public string Sync { get; set; }
-
- [JsonProperty("modified")]
- public DateTime Modified { get; set; }
-
- public MetadataInfo()
- {
-
- }
-
- public MetadataInfo(Metadata metadata, DateTime modified)
- {
- Name = metadata.Table.Name;
- TableName = metadata.Table.TableName;
- Info = metadata.Table.Info;
- Sync = metadata.Table.EnableSynchronism ? "1" : "0";
- Modified = modified;
- }
-
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataOptions.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataOptions.cs
deleted file mode 100644
index 65688e4c9..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigration/MetadataOptions.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-#nullable disable
-using JJMasterData.Core.DataDictionary.Models;
-using Newtonsoft.Json;
-
-namespace JJMasterData.LegacyMetadataMigrator.FormElementMigration;
-
-
-public class MetadataOptions
-{
- [JsonProperty("grid")]
- public GridUI Grid { get; set; } = new();
-
- [JsonProperty("form")]
- public FormUI Form { get; set; } = new();
-
- [JsonProperty("toolBarActions")]
- public GridToolbarActions ToolbarActions { get; set; } = new();
-
- [JsonProperty("gridActions")]
- public GridActions GridActions { get; set; } = new();
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigrationService.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigrationService.cs
deleted file mode 100644
index 7c24d7bf5..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/FormElementMigrationService.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using JJMasterData.Commons.Configuration.Options;
-using JJMasterData.Commons.Data;
-using JJMasterData.Commons.Exceptions;
-using JJMasterData.Core.Configuration.Options;
-using JJMasterData.Core.DataDictionary.Repository.Abstractions;
-using Microsoft.Extensions.Options;
-
-namespace JJMasterData.LegacyMetadataMigrator;
-
-public class FormElementMigrationService(IDataDictionaryRepository dataDictionaryRepository,
- MetadataRepository metadataRepository,
- IOptions commonsOptions,
- IOptions options,
- ExpressionsMigrationService expressionsMigrationService)
-{
- private DataAccess? _dataAccess;
- private IDataDictionaryRepository DataDictionaryRepository { get; } = dataDictionaryRepository;
- private MetadataRepository MetadataRepository { get; } = metadataRepository;
- private ExpressionsMigrationService ExpressionsMigrationService { get; } = expressionsMigrationService;
-
- private DataAccess DataAccess
- {
- get
- {
- if (_dataAccess == null)
- {
- var connStr = commonsOptions.Value.ConnectionString;
- var connProvider = commonsOptions.Value.ConnectionProvider;
-
- if (connStr == null)
- throw new DataAccessException("Connection string not found");
-
- _dataAccess = new(connStr, connProvider);
- }
-
- return _dataAccess;
- }
- }
-
- private string TableName => Options.DataDictionaryTableName;
- private MasterDataCoreOptions Options { get; } = options.Value;
-
- public void Migrate()
- {
- var start = DateTime.Now;
-
- var containsLegacyType = DataAccess.GetResult($"SELECT [type] from {TableName} where [type] <> 'F'");
-
- if (containsLegacyType is null)
- {
- Console.WriteLine("✅ DataDictionary is already migrated");
- return;
- }
-
- var databaseDictionaries = MetadataRepository.GetMetadataList();
-
- DataAccess.SetCommand($"DROP TABLE {TableName}");
- // DataAccess.SetCommand($"DROP PROCEDURE {Options.GetReadProcedureName(TableName)}");
- // DataAccess.SetCommand($"DROP PROCEDURE {Options.GetWriteProcedureName(TableName)}");
-
- DataDictionaryRepository.CreateStructureIfNotExistsAsync().GetAwaiter().GetResult();
-
- Console.WriteLine("\u2705 Re-created {0} and all related stored procedures", TableName);
-
- foreach (var metadata in databaseDictionaries)
- {
- var formElement = metadata.GetFormElement();
-
- formElement.UseReadProcedure = true;
- formElement.UseWriteProcedure = true;
-
- foreach (var field in formElement.Fields)
- {
- if (field.DataFile is not null)
- {
- field.DataFile.MaxFileSize /= 1000000;
- }
- }
-
- DataDictionaryRepository.InsertOrReplaceAsync(formElement).GetAwaiter().GetResult();
- Console.WriteLine("\u2705 {0}", formElement.Name);
- }
-
- DataAccess.SetCommand($"delete from {TableName} where type <> 'F'");
-
- DataAccess.SetCommand($$"""
- UPDATE {{TableName}}
- SET [json] = REPLACE([json],
- '{search_id}',
- '{SearchId}')
- WHERE [json] LIKE '%{search_id}%';
- """);
-
- Console.WriteLine("✅ Replaced {{search_id}} to {{SearchId}} in all elements");
-
- DataAccess.SetCommand($$"""
- UPDATE {{TableName}}
- SET [json] = REPLACE([json],
- '{search_text}',
- '{SearchText}')
- WHERE [json] LIKE '%{search_text}%';
- """);
-
- Console.WriteLine("✅ Replaced {{search_text}} to {{SearchText}} in all elements");
-
- DataAccess.SetCommand($$"""
- UPDATE {{TableName}}
- SET [json] = REPLACE([json],
- '{objname}',
- '{FieldName}')
- WHERE [json] LIKE '%{objname}%';
- """);
-
- Console.WriteLine("✅ Replaced {{objname}} to {{FieldName}} in all elements");
-
- Console.WriteLine($"Process started: {start}");
- Console.WriteLine($"Process finished: {DateTime.Now}");
-
- ExpressionsMigrationService.Migrate();
- }
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/MasterData.LegacyMetadataMigrator.csproj b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/MasterData.LegacyMetadataMigrator.csproj
deleted file mode 100644
index e72049fdb..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/MasterData.LegacyMetadataMigrator.csproj
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- Exe
- net10.0
- enable
- enable
-
- JJMasterData.LegacyMetadataMigrator
- JJMasterData.LegacyMetadataMigrator
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/MetadataRepository.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/MetadataRepository.cs
deleted file mode 100644
index 7296a64bd..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/MetadataRepository.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-#nullable disable
-
-using JJMasterData.Commons.Data.Entity.Models;
-using JJMasterData.Commons.Data.Entity.Repository;
-using JJMasterData.Commons.Data.Entity.Repository.Abstractions;
-using JJMasterData.Core.Configuration.Options;
-using JJMasterData.Core.DataDictionary.Models;
-using JJMasterData.Core.DataDictionary.Models.Actions;
-using JJMasterData.Core.DataDictionary.Repository.Abstractions;
-using JJMasterData.Core.DataDictionary.Structure;
-using JJMasterData.LegacyMetadataMigrator.FormElementMigration;
-using Microsoft.Extensions.Options;
-using Newtonsoft.Json;
-
-namespace JJMasterData.LegacyMetadataMigrator;
-
-public class MetadataRepository(IEntityRepository entityRepository, IOptions options)
-{
- private Element _masterDataElement;
-
- internal Element MasterDataElement
- {
- get
- {
- if (_masterDataElement == null)
- {
- var tableName = options.Value.DataDictionaryTableName;
- _masterDataElement = DataDictionaryStructure.GetElement("dbo", tableName);
- }
- return _masterDataElement;
- }
- }
-
- ///
- public IEnumerable GetMetadataList(bool? sync = null)
- {
- var list = new List();
- var entityParameters = new EntityParameters();
- entityParameters.OrderBy.AddOrReplace("name", OrderByDirection.Asc);
- entityParameters.OrderBy.AddOrReplace("type", OrderByDirection.Asc);
- if (sync.HasValue)
- entityParameters.Filters.Add("sync", (bool)sync ? "1" : "0");
-
- MasterDataElement.Fields.Add(new ElementField
- {
- Name = "namefilter",
- Filter = new ElementFilter(FilterMode.Contain),
- DataBehavior = FieldBehavior.ViewOnly
- });
-
- //Ignore procedures to apply compatibility
- MasterDataElement.UseReadProcedure = false;
- MasterDataElement.UseWriteProcedure = false;
-
- string currentName = "";
- var dt = entityRepository.GetDictionaryListResultAsync(MasterDataElement,entityParameters, false).GetAwaiter().GetResult();
- Metadata currentParser = null;
- foreach (var row in dt.Data)
- {
- string name = row["name"].ToString();
- if (!currentName.Equals(name))
- {
- ApplyCompatibility(currentParser);
-
- currentName = name;
- list.Add(new Metadata());
- currentParser = list[^1];
- }
-
- string json = row["json"].ToString();
- var type = row["type"].ToString()!;
- switch (type)
- {
- case "T":
- currentParser!.Table = JsonConvert.DeserializeObject(json);
- break;
- case "F":
- currentParser!.Form = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
- {
- Error = (sender, args) =>
- {
- args.ErrorContext.Handled = true;
- }
- });
- break;
- case "L":
- currentParser!.Options = JsonConvert.DeserializeObject(json);
- break;
- case "A":
- currentParser!.ApiOptions = JsonConvert.DeserializeObject(json);
- break;
- }
- }
-
- ApplyCompatibility(currentParser);
-
- return list;
- }
-
-
- public static void ApplyCompatibility(Metadata dicParser)
- {
- if (dicParser?.Table == null)
- return;
-
- //Nairobi
- dicParser.Options ??= new MetadataOptions();
-
- dicParser.Options.ToolbarActions ??= new GridToolbarActions();
-
- dicParser.Options.GridActions ??= new GridActions();
-
-
- //Denver
- if (dicParser.ApiOptions == null)
- {
- dicParser.ApiOptions = new MetadataApiOptions();
- if (dicParser.Table.EnableSynchronism)
- {
- dicParser.ApiOptions.EnableGetAll = true;
- dicParser.ApiOptions.EnableGetDetail = true;
- dicParser.ApiOptions.EnableAdd = true;
- dicParser.ApiOptions.EnableUpdate = true;
- dicParser.ApiOptions.EnableUpdatePart = true;
- dicParser.ApiOptions.EnableDel = true;
- }
- }
-
- if (string.IsNullOrEmpty(dicParser.Table.TableName))
- {
- dicParser.Table.TableName = dicParser.Table.Name;
- }
-
- //Tokio
- if (dicParser.Form is { Panels: null }) dicParser.Form.Panels = [];
-
- //Professor
- if (dicParser.Form != null)
- {
- foreach (var field in dicParser.Form.FormFields)
- {
- if (field.DataItem is not { DataItemType: DataItemType.Manual })
- continue;
-
- if (field.DataItem.Command != null && !string.IsNullOrEmpty(field.DataItem.Command.Sql))
- field.DataItem.DataItemType = DataItemType.SqlCommand;
- else if (field.DataItem.ElementMap != null && !string.IsNullOrEmpty(field.DataItem.ElementMap.ElementName))
- field.DataItem.DataItemType = DataItemType.ElementMap;
- }
- }
-
- //Arturito
- // foreach (var action in dicParser.Options.GridActions.GetAll()
- // .Where(action => action is UrlRedirectAction or InternalAction or ScriptAction or SqlCommandAction))
- // {
- // //action.IsUserCreated = true;
- // }
- //
- // foreach (var action in dicParser.Options.ToolbarActions
- // .GetAll()
- // .Where(action => action is UrlRedirectAction or InternalAction or ScriptAction or SqlCommandAction))
- // {
- // //action.IsUserCreated = true;
- // }
-
-
- //Sirius
-
- dicParser.Options.ToolbarActions.ExportAction.ProcessOptions ??= new ProcessOptions();
-
- dicParser.Options.ToolbarActions.ImportAction.ProcessOptions ??= new ProcessOptions();
- }
-}
\ No newline at end of file
diff --git a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/Program.cs b/src/ConsoleApps/MasterData.LegacyMetadataMigrator/Program.cs
deleted file mode 100644
index 759bb5798..000000000
--- a/src/ConsoleApps/MasterData.LegacyMetadataMigrator/Program.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using JJMasterData.Core.Configuration;
-using JJMasterData.LegacyMetadataMigrator;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-
-var services = new ServiceCollection();
-var configurationBuilder = new ConfigurationBuilder();
-configurationBuilder.AddJsonFile("appsettings.json");
-services.AddJJMasterDataCore();
-
-services.AddSingleton(configurationBuilder.Build());
-services.AddTransient();
-services.AddTransient();
-services.AddTransient();
-
-var serviceProvider = services.BuildServiceProvider();
-
-var service = serviceProvider.GetRequiredService();
-
-service.Migrate();
\ No newline at end of file
diff --git a/src/MasterData.Commons/Configuration/MasterDataServiceBuilder.cs b/src/MasterData.Commons/Configuration/MasterDataServiceBuilder.cs
index 69ccb697f..c99732c64 100644
--- a/src/MasterData.Commons/Configuration/MasterDataServiceBuilder.cs
+++ b/src/MasterData.Commons/Configuration/MasterDataServiceBuilder.cs
@@ -10,7 +10,7 @@
namespace JJMasterData.Commons.Configuration;
-public class MasterDataServiceBuilder(IServiceCollection services)
+public class MasterDataServiceBuilder(IServiceCollection services)
{
public IServiceCollection Services { get; } = services;
@@ -66,8 +66,7 @@ public MasterDataServiceBuilder WithEntityRepository() where T : IEntityRepos
return this;
}
- public MasterDataServiceBuilder WithEntityRepository(
- Func implementationFactory)
+ public MasterDataServiceBuilder WithEntityRepository(Func implementationFactory)
{
Services.Replace(ServiceDescriptor.Transient(implementationFactory));
return this;
diff --git a/src/MasterData.Commons/Configuration/Options/MasterDataCommonsOptions.cs b/src/MasterData.Commons/Configuration/Options/MasterDataCommonsOptions.cs
index 9ba14eca1..d0b425d9d 100644
--- a/src/MasterData.Commons/Configuration/Options/MasterDataCommonsOptions.cs
+++ b/src/MasterData.Commons/Configuration/Options/MasterDataCommonsOptions.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
-using System.Runtime.InteropServices;
using System.Text.Json.Serialization;
using JJMasterData.Commons.Data;
using JJMasterData.Commons.Data.Entity.Models;
@@ -16,7 +15,6 @@ namespace JJMasterData.Commons.Configuration.Options;
///
/// JJMasterData key/value configurations.
/// They're populated from JJMasterData section on , following its implementations.
-/// On .NET Framework, add an builder to your application.
///
public sealed class MasterDataCommonsOptions
{
@@ -47,15 +45,6 @@ public sealed class MasterDataCommonsOptions
[Display(Name = "Write Procedure Pattern")]
public string WriteProcedurePattern { get; set; } = "{tablename}Set";
- ///
- /// Secret key used at JJMasterDataEncryptionService
- ///
- [Display(Name = "Cryptography Secret Key")]
- public string? SecretKey { get; set; }
-
- [JsonIgnore]
- public static bool IsNetFramework { get; } = RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework");
-
internal ConnectionString GetConnectionString(Guid? guid)
{
if (guid is null)
@@ -131,4 +120,4 @@ public static string RemoveTbPrefix(string tableName)
return tableName;
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Commons/Configuration/ServiceCollectionExtensions.cs b/src/MasterData.Commons/Configuration/ServiceCollectionExtensions.cs
index 9412f9678..f78954513 100644
--- a/src/MasterData.Commons/Configuration/ServiceCollectionExtensions.cs
+++ b/src/MasterData.Commons/Configuration/ServiceCollectionExtensions.cs
@@ -1,4 +1,5 @@
using System;
+using JJConsulting.MasterData.Storage.Abstractions;
using JJMasterData.Commons.Configuration.Options;
using JJMasterData.Commons.Data;
using JJMasterData.Commons.Data.Entity.Providers;
@@ -6,78 +7,89 @@
using JJMasterData.Commons.Data.Entity.Repository.Abstractions;
using JJMasterData.Commons.Security.Cryptography;
using JJMasterData.Commons.Security.Cryptography.Abstractions;
+using JJMasterData.Commons.Security;
+using JJMasterData.Commons.Storage;
using JJMasterData.Commons.Tasks;
using JJMasterData.Commons.Util;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Localization;
+using Microsoft.Extensions.DependencyInjection.Extensions;
namespace JJMasterData.Commons.Configuration;
public static class ServiceCollectionExtensions
{
- public static MasterDataServiceBuilder AddJJMasterDataCommons(this IServiceCollection services)
+ extension(IServiceCollection services)
{
- var builder = new MasterDataServiceBuilder(services);
+ public MasterDataServiceBuilder AddJJMasterDataCommons()
+ {
+ var builder = new MasterDataServiceBuilder(services);
- services.AddMasterDataCommonsServices();
+ services.AddMasterDataCommonsServices();
- return builder;
- }
+ return builder;
+ }
- public static MasterDataServiceBuilder AddJJMasterDataCommons(this IServiceCollection services,
- IConfiguration configuration)
- {
- var builder = new MasterDataServiceBuilder(services);
+ public MasterDataServiceBuilder AddJJMasterDataCommons(IConfiguration configuration)
+ {
+ var builder = new MasterDataServiceBuilder(services);
- builder.Services.Configure(configuration.GetJJMasterData());
+ builder.Services.Configure(configuration.GetJJMasterData());
- services.AddMasterDataCommonsServices();
+ services.AddMasterDataCommonsServices();
- return builder;
- }
+ return builder;
+ }
- public static MasterDataServiceBuilder AddJJMasterDataCommons(this IServiceCollection services,
- Action configure)
- {
- var builder = new MasterDataServiceBuilder(services);
+ public MasterDataServiceBuilder AddJJMasterDataCommons(Action configure)
+ {
+ var builder = new MasterDataServiceBuilder(services);
- services.AddMasterDataCommonsServices();
- if (configure != null)
- services.PostConfigure(configure);
+ services.AddMasterDataCommonsServices();
+ if (configure != null)
+ services.PostConfigure(configure);
- return builder;
- }
-
- private static void AddMasterDataCommonsServices(this IServiceCollection services)
- {
- services.AddOptions()
- .BindConfiguration("JJMasterData")
- .Validate(o => !string.IsNullOrEmpty(o.ConnectionString),
- "Connection string is required at JJMasterData:ConnectionString at your configuration source.")
- .Validate(o => !string.IsNullOrEmpty(o.SecretKey),
- "Secret key is required at JJMasterData:SecretKey at your configuration source.")
- .ValidateOnStart();
-
- services.AddScoped();
+ return builder;
+ }
- services.AddOptions().BindConfiguration("JJMasterData");
- services.AddTransient();
- services.AddTransient();
- services.AddTransient();
+ private void AddMasterDataCommonsServices()
+ {
+ services.AddOptions()
+ .BindConfiguration("JJMasterData")
+ .Validate(o => !string.IsNullOrEmpty(o.ConnectionString),
+ "Connection string is required at JJMasterData:ConnectionString at your configuration source.")
+ .ValidateOnStart();
-#pragma warning disable CS0618 // Type or member is obsolete
- services.AddTransient();
-#pragma warning restore CS0618 // Type or member is obsolete
- services.AddTransient();
- services.AddTransient();
- services.AddTransient();
-
- services.AddTransient();
- services.AddTransient();
+ services.TryAddTransient();
+
+ services.AddOptions()
+ .BindConfiguration("HmacOptions")
+ .Configure((options, configuration) =>
+ {
+ if (string.IsNullOrWhiteSpace(options.SecretKey))
+ options.SecretKey = configuration["JJMasterData:SecretKey"] ?? string.Empty;
+ });
+
+ services.TryAddScoped();
- services.AddSingleton();
-
- services.AddScoped();
+ services.AddDataProtection();
+
+ services.AddOptions().BindConfiguration("JJMasterData");
+
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
+
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
+
+ services.TryAddTransient();
+
+ services.TryAddTransient();
+
+ services.TryAddTransient();
+ services.TryAddSingleton();
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Commons/Data/DataAccessAsync.cs b/src/MasterData.Commons/Data/DataAccessAsync.cs
index 9371d5508..21605ccc2 100644
--- a/src/MasterData.Commons/Data/DataAccessAsync.cs
+++ b/src/MasterData.Commons/Data/DataAccessAsync.cs
@@ -72,12 +72,12 @@ private async Task ExecuteDataCommandAsync(
{
try
{
- using var dbCommand = CreateDbCommand(command);
+ await using var dbCommand = CreateDbCommand(command);
dbCommand.Connection = await CreateConnectionAsync(cancellationToken);
- using (dbCommand.Connection)
+ await using (dbCommand.Connection)
{
- using (var reader = await dbCommand.ExecuteReaderAsync(cancellationToken))
+ await using (var reader = await dbCommand.ExecuteReaderAsync(cancellationToken))
{
await readerAction(reader, state, cancellationToken);
@@ -103,9 +103,9 @@ private async Task ExecuteDataCommandAsync(
object? scalarResult;
try
{
- using var dbCommand = CreateDbCommand(command);
+ await using var dbCommand = CreateDbCommand(command);
dbCommand.Connection = await CreateConnectionAsync(cancellationToken);
- using (dbCommand.Connection)
+ await using (dbCommand.Connection)
{
scalarResult = await dbCommand.ExecuteScalarAsync(cancellationToken);
@@ -126,9 +126,9 @@ public async Task SetCommandAsync(DataAccessCommand command, CancellationTo
int rowsAffected;
try
{
- using var dbCommand = CreateDbCommand(command);
+ await using var dbCommand = CreateDbCommand(command);
dbCommand.Connection = await CreateConnectionAsync(cancellationToken);
- using (dbCommand.Connection)
+ await using (dbCommand.Connection)
{
rowsAffected = await dbCommand.ExecuteNonQueryAsync(cancellationToken);
@@ -150,37 +150,25 @@ public async Task SetCommandListAsync(IEnumerable comman
int numberOfRowsAffected = 0;
DataAccessCommand? currentCommand = null;
- using var connection = await CreateConnectionAsync(cancellationToken);
+ await using var connection = await CreateConnectionAsync(cancellationToken);
-#if NET48
- using var transaction = connection.BeginTransaction();
-#else
- using var transaction = await connection.BeginTransactionAsync(cancellationToken);
-#endif
+ await using var transaction = await connection.BeginTransactionAsync(cancellationToken);
try
{
foreach (var command in commands)
{
currentCommand = command;
- using var dbCommand = CreateDbCommand(command);
+ await using var dbCommand = CreateDbCommand(command);
dbCommand.Connection = connection;
dbCommand.Transaction = transaction;
numberOfRowsAffected += await dbCommand.ExecuteNonQueryAsync(cancellationToken);
}
-#if NET48
- transaction.Commit();
-#else
await transaction.CommitAsync(cancellationToken);
-#endif
}
catch (Exception ex)
{
-#if NET48
- transaction.Rollback();
-#else
await transaction.RollbackAsync(cancellationToken);
-#endif
throw GetDataAccessException(ex, currentCommand);
}
@@ -234,13 +222,13 @@ private async Task GetDataAsync(
{
try
{
- using var dbCommand = CreateDbCommand(command);
+ await using var dbCommand = CreateDbCommand(command);
dbCommand.Connection = await CreateConnectionAsync(cancellationToken);
- using (dbCommand.Connection)
+ await using (dbCommand.Connection)
{
- using (var dataReader =
- await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow, cancellationToken))
+ await using (var dataReader =
+ await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow, cancellationToken))
{
while (await dataReader.ReadAsync(cancellationToken))
{
@@ -273,11 +261,11 @@ await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow, cancellationToken)
try
{
- using var dbCommand = CreateDbCommand(command);
+ await using var dbCommand = CreateDbCommand(command);
dbCommand.Connection = await CreateConnectionAsync(cancellationToken);
- using var connection = dbCommand.Connection;
- using (var dataReader = await dbCommand.ExecuteReaderAsync(cancellationToken))
+ await using var connection = dbCommand.Connection;
+ await using (var dataReader = await dbCommand.ExecuteReaderAsync(cancellationToken))
{
List columnNames = [];
@@ -342,7 +330,7 @@ public async Task TryConnectionAsync(CancellationToken cancell
{
if (connection.State == ConnectionState.Open)
{
- connection.Close();
+ await connection.CloseAsync();
}
connection.Dispose();
@@ -397,4 +385,4 @@ public async Task ExecuteBatchAsync(string script, int? timeoutSeconds = n
return true;
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Commons/Data/DataAccessProviderHelper.cs b/src/MasterData.Commons/Data/DataAccessProviderHelper.cs
index 716fcf602..cc7e4fcb5 100644
--- a/src/MasterData.Commons/Data/DataAccessProviderHelper.cs
+++ b/src/MasterData.Commons/Data/DataAccessProviderHelper.cs
@@ -33,8 +33,7 @@ public static DataAccessProvider GetDataAccessProviderFromString(string provider
"Oracle.ManagedDataAccess.Core.Client" => DataAccessProvider.OracleNetCore,
"MySql" => DataAccessProvider.MySql,
"MySql.Data.MySqlClient.MySqlClientFactory" => DataAccessProvider.MySql,
- "PostgreSql" => DataAccessProvider.PostgreSql,
- "Npgsql.NpgsqlFactory" => DataAccessProvider.PostgreSql,
+ "PostgreSql" or "Npgsql.NpgsqlFactory" => DataAccessProvider.PostgreSql,
_ => throw new DataAccessProviderException("Unknown data access provider name.")
};
}
diff --git a/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerAlterTableScripts.cs b/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerAlterTableScripts.cs
index e1b477529..f22746c35 100644
--- a/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerAlterTableScripts.cs
+++ b/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerAlterTableScripts.cs
@@ -1,11 +1,12 @@
using System.Collections.Generic;
using System.Linq;
+using System.Text;
using JetBrains.Annotations;
using JJMasterData.Commons.Data.Entity.Models;
namespace JJMasterData.Commons.Data.Entity.Providers;
-public class SqlServerAlterTableScripts : SqlServerScriptsBase
+public static class SqlServerAlterTableScripts
{
[CanBeNull]
public static string GetAlterTableScript(Element element, IEnumerable fields)
@@ -13,21 +14,26 @@ public static string GetAlterTableScript(Element element, IEnumerable relationships)
{
@@ -21,7 +21,7 @@ public static string GetCreateTableScript(Element element, List 0)
@@ -50,7 +50,7 @@ public static string GetCreateTableScript(Element element, List 0)
{
sql.AppendLine(", ");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append("CONSTRAINT [PK_");
sql.Append(element.TableName);
sql.Append("] PRIMARY KEY NONCLUSTERED (");
@@ -79,21 +79,21 @@ public static string GetCreateTableScript(Element element, List 0)
sql.AppendLine(", ");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append(index.Columns[i]);
}
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine(")");
sql.AppendLine("GO");
counter++;
@@ -143,7 +143,7 @@ private static string GetRelationshipsScript(Element element, List options,
IOptionsSnapshot sqlServerOptions)
- : SqlServerScriptsBase
{
public string GetReadProcedureScript(Element element)
{
@@ -34,13 +32,15 @@ public string GetReadProcedureScript(Element element)
}
else
{
- sql.AppendLine(GetSqlDropIfExists(procedureName));
+ sql.Append(SqlServerScriptsHelper.GetSqlDropIfExists(procedureName));
+ sql.AppendLine();
sql.Append("CREATE PROCEDURE ");
}
sql.AppendLine(procedureName);
sql.AppendLine("@orderby VARCHAR(MAX), ");
- sql.AppendLine(GetParameters(fields, addMasterDataParameters: true));
+ sql.Append(GetParameters(fields, addMasterDataParameters: true));
+ sql.AppendLine();
sql.AppendLine("AS ");
sql.AppendLine("BEGIN ");
sql.Append(GetReadScript(element, fields));
@@ -49,41 +49,41 @@ public string GetReadProcedureScript(Element element)
return sql.ToString();
}
- internal string GetReadScript(Element element, List fields)
+ internal StringBuilder GetReadScript(Element element, List fields)
{
var sql = new StringBuilder();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("DECLARE @sqlColumn NVARCHAR(MAX)");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("DECLARE @sqlTable NVARCHAR(MAX)");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("DECLARE @sqlWhere NVARCHAR(MAX)");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("DECLARE @sqlOrderBy NVARCHAR(MAX)");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("DECLARE @sqlOffset NVARCHAR(MAX)");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("DECLARE @query NVARCHAR(MAX)");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
if (fields.Exists(f => f.Filter.Type is FilterMode.MultValuesContain or FilterMode.MultValuesEqual))
{
sql.AppendLine("DECLARE @sqlLikeIn NVARCHAR(MAX)");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
}
sql.AppendLine("DECLARE @count INT");
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("--COLUMNS");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlColumn = '");
var index = 1;
foreach (var field in fields)
{
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
sql.Append("");
if (field.DataBehavior == FieldBehavior.ViewOnly)
{
@@ -104,20 +104,20 @@ internal string GetReadScript(Element element, List fields)
index++;
}
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine(" '");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("--TABLES");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append("SET @sqlTable = 'FROM ");
- sql.Append(GetTableName(element));
+ sql.Append(SqlServerScriptsHelper.GetTableName(element));
sql.AppendLine(" WITH (NOLOCK)'");
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("--CONDITIONALS");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlWhere = ' WHERE 1=1 '");
foreach (var field in fields)
@@ -127,7 +127,7 @@ internal string GetReadScript(Element element, List fields)
if (field.DataBehavior == FieldBehavior.ViewOnly)
{
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("/*");
sql.Append("TODO: FILTER ");
sql.AppendLine($"[{field.Name}]");
@@ -142,11 +142,11 @@ internal string GetReadScript(Element element, List fields)
if (field.DataType is FieldType.Date or FieldType.DateTime or FieldType.DateTime2)
{
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append("IF @");
sql.Append(field.Name);
sql.AppendLine("_from IS NOT NULL");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append("SET @sqlWhere = @sqlWhere + ' AND CONVERT(DATE, ");
sql.Append($"[{field.Name}]");
sql.Append(") BETWEEN CONVERT(VARCHAR(10), @");
@@ -157,11 +157,11 @@ internal string GetReadScript(Element element, List fields)
}
else
{
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append("IF @");
sql.Append(field.Name);
sql.AppendLine("_from IS NOT NULL");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append("SET @sqlWhere = @sqlWhere + ' AND ");
sql.Append($"[{field.Name}]");
sql.Append(" BETWEEN @");
@@ -176,11 +176,11 @@ internal string GetReadScript(Element element, List fields)
}
case FilterMode.Contain:
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append("IF @");
sql.Append(field.Name);
sql.AppendLine(" IS NOT NULL");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append("SET @sqlWhere = @sqlWhere + ' AND ");
sql.Append($"[{field.Name}]");
sql.Append($" LIKE ''%'' + RTRIM(@{field.Name}) + ''%'' '");
@@ -196,11 +196,11 @@ internal string GetReadScript(Element element, List fields)
if (field.Filter.Type == FilterMode.Equal || field.IsPk)
{
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append("IF @");
sql.Append(field.Name);
sql.AppendLine(" IS NOT NULL");
- sql.Append(Tab,2);
+ sql.Append(SqlServerScriptsHelper.Tab,2);
sql.Append("SET @sqlWhere = @sqlWhere + ' AND ");
sql.Append($"[{field.Name}] = @{field.Name}'");
}
@@ -214,14 +214,14 @@ internal string GetReadScript(Element element, List fields)
if (field.DataBehavior != FieldBehavior.ViewOnly)
continue;
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("*/");
}
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("--ORDER BY");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
var listPk = fields.FindAll(x => x.IsPk);
if (listPk.Count == 0)
{
@@ -236,154 +236,154 @@ internal string GetReadScript(Element element, List fields)
sql.AppendLine("'");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("IF @orderby IS NOT NULL AND @orderby <> ''");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("BEGIN");
- sql.Append(Tab);
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlOrderBy = ' ORDER BY ' + @orderby");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("END");
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("--PAGINATION");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("IF @pag < 1");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append("SET @pag = 1");
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlOffset = ' '");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlOffset = @sqlOffset + ' OFFSET ('");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlOffset = @sqlOffset + '(@pag - 1)'");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlOffset = @sqlOffset + ' * '");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlOffset = @sqlOffset + '@regporpag'");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlOffset = @sqlOffset + ') ROWS FETCH NEXT '");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlOffset = @sqlOffset + '@regporpag'");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @sqlOffset = @sqlOffset + ' ROWS ONLY '");
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("--TOTAL OF RECORDS");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("IF @qtdtotal is null or @qtdtotal = 0");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("BEGIN");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("SET @qtdtotal = 0;");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("SET @query = N'SELECT @count = COUNT(*) ' + @sqlTable + @sqlWhere");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("EXECUTE sp_executesql @query,");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append("N'");
sql.Append(GetParameters(fields, addMasterDataParameters: false, tabLevel: 2));
sql.Append("@count int output',");
sql.AppendLine();
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append(GetFilterParametersScript(fields, tabCount: 2));
sql.Append("@count = @qtdtotal output");
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("END");
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("--DATASET RESULT");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @query = N'SELECT ' + @sqlColumn + @sqlTable + @sqlWhere + @sqlOrderBy + @sqlOffset");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("EXECUTE sp_executesql @query,");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append("N'");
sql.Append(GetParameters(fields, addMasterDataParameters: true, tabLevel: 1));
sql.Append('\'');
sql.Append(',');
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append(GetFilterParametersScript(fields));
sql.AppendLine("@regporpag,");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("@pag,");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("@qtdtotal");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine();
- return sql.ToString();
+ return sql;
}
- private string GetMultValuesEquals(string fieldName)
+ private StringBuilder GetMultValuesEquals(string fieldName)
{
var sql = new StringBuilder();
if (sqlServerOptions.Value.CompatibilityLevel < 130)
{
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append("IF @");
sql.Append(fieldName);
sql.AppendLine(" IS NOT NULL");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("BEGIN");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendFormat("SET @likein = ' AND {0} IN ('", fieldName);
sql.AppendLine();
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendFormat("WHILE CHARINDEX(',', @{0}) <> 0", fieldName);
sql.AppendLine();
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("BEGIN");
- sql.Append(Tab, 3);
+ sql.Append(SqlServerScriptsHelper.Tab, 3);
sql.AppendFormat("SET @likein = @likein + CHAR(39) + SUBSTRING(@{0},1,CHARINDEX(',',@{0}) -1) + CHAR(39);", fieldName);
sql.AppendLine();
- sql.Append(Tab, 3);
+ sql.Append(SqlServerScriptsHelper.Tab, 3);
sql.AppendFormat("SET @{0} = RIGHT(@{0} , LEN(@{0}) - CHARINDEX(',', @{0}));", fieldName);
sql.AppendLine();
- sql.Append(Tab, 3);
+ sql.Append(SqlServerScriptsHelper.Tab, 3);
sql.AppendLine("SET @likein = @likein + ', ';");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("END");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendFormat("SET @likein = @likein + CHAR(39) + @{0} + CHAR(39) + ') '", fieldName);
sql.AppendLine();
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("SET @sqlcond = @sqlcond + @likein");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("END");
}
else
{
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append($"IF @{fieldName} IS NOT NULL");
sql.AppendLine();
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append("BEGIN");
sql.AppendLine();
- sql.Append(Tab, 3);
+ sql.Append(SqlServerScriptsHelper.Tab, 3);
sql.Append($"SET @sqlWhere = @sqlWhere + ' AND [{fieldName}] IN (SELECT value FROM STRING_SPLIT(@{fieldName}, '',''))'");
sql.AppendLine();
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append("END");
}
- return sql.ToString();
+ return sql;
}
- private static string GetFilterParametersScript(List fields, int tabCount = 1)
+ private static StringBuilder GetFilterParametersScript(List fields, int tabCount = 1)
{
var sql = new StringBuilder();
@@ -394,7 +394,7 @@ private static string GetFilterParametersScript(List fields, int t
if (field.Filter.Type is FilterMode.Range)
{
sql.AppendLine($"@{field.Name}_from,");
- sql.Append(Tab, tabCount);
+ sql.Append(SqlServerScriptsHelper.Tab, tabCount);
sql.AppendLine($"@{field.Name}_to,");
}
else
@@ -402,11 +402,11 @@ private static string GetFilterParametersScript(List fields, int t
sql.AppendLine($"@{field.Name},");
}
- sql.Append(Tab, tabCount);
+ sql.Append(SqlServerScriptsHelper.Tab, tabCount);
}
}
- return sql.ToString();
+ return sql;
}
private static bool IsFilter(ElementField field)
@@ -414,7 +414,7 @@ private static bool IsFilter(ElementField field)
return field.Filter.Type != FilterMode.None || field.IsPk;
}
- private static string GetParameters(List fields, bool addMasterDataParameters, int tabLevel = 0)
+ private static StringBuilder GetParameters(List fields, bool addMasterDataParameters, int tabLevel = 0)
{
var sql = new StringBuilder();
@@ -436,11 +436,11 @@ private static string GetParameters(List fields, bool addMasterDat
{
size = $"({field.Size},{field.NumberOfDecimalPlaces})";
}
- sql.Append(Tab, tabLevel);
+ sql.Append(SqlServerScriptsHelper.Tab, tabLevel);
sql.AppendLine($"@{field.Name}_from {typeName}{size},");
- sql.Append(Tab, tabLevel);
+ sql.Append(SqlServerScriptsHelper.Tab, tabLevel);
sql.AppendLine($"@{field.Name}_to {typeName}{size},");
- sql.Append(Tab, tabLevel);
+ sql.Append(SqlServerScriptsHelper.Tab, tabLevel);
break;
}
@@ -465,7 +465,7 @@ private static string GetParameters(List fields, bool addMasterDat
sql.AppendLine(", ");
}
- sql.Append(Tab, tabLevel);
+ sql.Append(SqlServerScriptsHelper.Tab, tabLevel);
}
break;
@@ -476,30 +476,30 @@ private static string GetParameters(List fields, bool addMasterDat
if (addMasterDataParameters)
{
sql.AppendLine("@regporpag INT, ");
- sql.Append(Tab, tabLevel);
+ sql.Append(SqlServerScriptsHelper.Tab, tabLevel);
sql.AppendLine("@pag INT, ");
- sql.Append(Tab, tabLevel);
+ sql.Append(SqlServerScriptsHelper.Tab, tabLevel);
sql.Append("@qtdtotal INT OUTPUT ");
}
- return sql.ToString();
+ return sql;
}
private string GetFilterMultValuesContains(string fieldName)
{
var sql = new StringBuilder();
sql.AppendLine();
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.Append("IF @");
sql.Append(fieldName);
sql.AppendLine(" IS NOT NULL");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("BEGIN");
if (sqlServerOptions.Value.CompatibilityLevel >= 130)
{
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append("SET @sqlWhere = @sqlWhere + ' AND ");
sql.Append($"""
EXISTS (
@@ -511,33 +511,33 @@ WHERE [{fieldName}] LIKE ''%'' + s.value + ''%''
}
else
{
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("DECLARE @likein NVARCHAR(MAX)");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("SET @likein = ' AND ( '");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append($"WHILE CHARINDEX(',', @{fieldName}) <> 0");
sql.AppendLine();
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("BEGIN");
- sql.Append(Tab, 3);
+ sql.Append(SqlServerScriptsHelper.Tab, 3);
sql.AppendFormat("SET @likein = @likein + '{0} LIKE ' + CHAR(39) + '%' + SUBSTRING(@{0}, 1, CHARINDEX(',', @{0}) -1) + '%' + CHAR(39);", fieldName);
sql.AppendLine();
- sql.Append(Tab, 3);
+ sql.Append(SqlServerScriptsHelper.Tab, 3);
sql.AppendFormat("SET @{0} = RIGHT(@{0} , LEN(@{0}) - CHARINDEX(',', @{0}));", fieldName);
sql.AppendLine();
- sql.Append(Tab, 3);
+ sql.Append(SqlServerScriptsHelper.Tab, 3);
sql.AppendLine("SET @likein = @likein + ' OR ';");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("END");
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendFormat("SET @likein = @likein + '{0} LIKE ' + CHAR(39) + '%' + @{0} + '%' + CHAR(39) + ' ) '", fieldName);
sql.AppendLine();
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.AppendLine("SET @sqlWhere = @sqlWhere + @likein");
}
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("END");
return sql.ToString();
diff --git a/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScripts.cs b/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScripts.cs
index c7d5fa7d5..ac6ce5d4e 100644
--- a/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScripts.cs
+++ b/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScripts.cs
@@ -28,7 +28,7 @@ public string GetReadScript(Element element)
{
var fields = element.Fields.FindAll(f => f.DataBehavior is FieldBehavior.Real);
- return readProcedureScripts.GetReadScript(element, fields);
+ return readProcedureScripts.GetReadScript(element, fields).ToString();
}
public static string GetCreateTableScript(Element element, List relationships)
diff --git a/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScriptsBase.cs b/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScriptsHelper.cs
similarity index 82%
rename from src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScriptsBase.cs
rename to src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScriptsHelper.cs
index c3edaa089..8e6f7c599 100644
--- a/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScriptsBase.cs
+++ b/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerScriptsHelper.cs
@@ -5,11 +5,11 @@
namespace JJMasterData.Commons.Data.Entity.Providers;
-public abstract class SqlServerScriptsBase
+internal static class SqlServerScriptsHelper
{
- protected const char Tab = '\t';
-
- protected static string GetTableName(Element element)
+ public const char Tab = '\t';
+
+ public static string GetTableName(Element element)
{
var sql = new StringBuilder();
@@ -24,7 +24,7 @@ protected static string GetTableName(Element element)
return sql.ToString();
}
- private static string GetFieldDataTypeScript(ElementField field)
+ public static StringBuilder GetFieldDataTypeScript(ElementField field)
{
var sql = new StringBuilder();
sql.Append(field.DataType.ToString());
@@ -55,10 +55,10 @@ private static string GetFieldDataTypeScript(ElementField field)
if (field is { AutoNum: true, DataType: not FieldType.UniqueIdentifier })
sql.Append(" IDENTITY ");
- return sql.ToString();
+ return sql;
}
- protected static string GetFieldDefinition(ElementField field)
+ public static StringBuilder GetFieldDefinition(ElementField field)
{
var sql = new StringBuilder();
sql.Append('[');
@@ -67,10 +67,10 @@ protected static string GetFieldDefinition(ElementField field)
sql.Append(GetFieldDataTypeScript(field));
- return sql.ToString();
+ return sql;
}
- protected static string GetSqlDropIfExists(string objname)
+ public static StringBuilder GetSqlDropIfExists(string objname)
{
var sql = new StringBuilder();
sql.AppendLine("IF EXISTS (SELECT * ");
@@ -90,6 +90,6 @@ protected static string GetSqlDropIfExists(string objname)
sql.AppendLine("END");
sql.AppendLine("GO");
- return sql.ToString();
+ return sql;
}
}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerWriteProcedureScripts.cs b/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerWriteProcedureScripts.cs
index a5a492c2e..6636c33b7 100644
--- a/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerWriteProcedureScripts.cs
+++ b/src/MasterData.Commons/Data/Entity/Providers/SqlServer/SqlServerWriteProcedureScripts.cs
@@ -11,7 +11,6 @@ namespace JJMasterData.Commons.Data.Entity.Providers;
public class SqlServerWriteProcedureScripts(
IOptionsSnapshot options,
IOptionsSnapshot sqlServerOptions)
- : SqlServerScriptsBase
{
private const string InsertInitial = "I";
private const string UpdateInitial = "A";
@@ -34,7 +33,8 @@ public string GetWriteProcedureScript(Element element)
}
else
{
- sql.AppendLine(GetSqlDropIfExists(procedureName));
+ sql.Append(SqlServerScriptsHelper.GetSqlDropIfExists(procedureName));
+ sql.AppendLine();
sql.Append("CREATE PROCEDURE ");
}
@@ -90,35 +90,35 @@ internal static string GetWriteScript(Element element, IReadOnlyCollection x.IsPk);
bool updateScript = HasUpdateFields(element);
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("DECLARE @TYPEACTION VARCHAR(1) ");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SET @TYPEACTION = @action ");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("IF @TYPEACTION = ' ' ");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("BEGIN ");
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
sql.AppendLine($"SET @TYPEACTION = '{InsertInitial}' ");
bool isFirst = true;
if (pks.Count > 0)
{
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("DECLARE @NCOUNT INT ");
sql.AppendLine(" ");
//Check
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("SELECT @NCOUNT = COUNT(*) ");
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
sql.Append("FROM ");
- sql.Append(GetTableName(element));
+ sql.Append(SqlServerScriptsHelper.GetTableName(element));
sql.AppendLine(" WITH (NOLOCK) ");
foreach (var f in pks)
{
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
if (isFirst)
{
sql.Append("WHERE ");
@@ -135,29 +135,29 @@ internal static string GetWriteScript(Element element, IReadOnlyCollection 0 ");
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("BEGIN ");
- sql.Append(Tab).Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
sql.AppendLine($"SET @TYPEACTION = '{UpdateInitial}'");
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("END ");
}
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("END ");
sql.AppendLine(" ");
//Insert Script
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine($"IF @TYPEACTION = '{InsertInitial}' ");
- sql.Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab);
sql.AppendLine("BEGIN ");
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
sql.Append("INSERT INTO ");
- sql.Append(GetTableName(element));
+ sql.Append(SqlServerScriptsHelper.GetTableName(element));
sql.AppendLine(" (");
isFirst = true;
@@ -180,7 +180,7 @@ internal static string GetWriteScript(Element element, IReadOnlyCollection 0)
{
- sql.Append(Tab, 2);
+ sql.Append(SqlServerScriptsHelper.Tab, 2);
sql.Append("OUTPUT ");
}
@@ -197,7 +197,7 @@ internal static string GetWriteScript(Element element, IReadOnlyCollection f.IsPk))
{
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
if (isFirst)
{
sql.Append("WHERE ");
@@ -272,25 +272,25 @@ internal static string GetWriteScript(Element element, IReadOnlyCollection f.IsPk && f.EnableOnDelete))
{
- sql.Append(Tab).Append(Tab);
+ sql.Append(SqlServerScriptsHelper.Tab).Append(SqlServerScriptsHelper.Tab);
if (isFirst)
{
sql.Append("WHERE ");
@@ -306,9 +306,9 @@ internal static string GetWriteScript(Element element, IReadOnlyCollection ExecuteBatchAsync(string script, Guid? connectionId = null)
public async Task> GetFieldsAsync(Element element, Dictionary primaryKeys)
{
if (primaryKeys.Count == 0)
- throw new ArgumentException("Your need at least one value at your primary keys.", nameof(primaryKeys));
+ throw new ArgumentException(@"Your need at least one value at your primary keys.", nameof(primaryKeys));
var totalOfRecords = new DataAccessParameter("@qtdtotal", 1, DbType.Int32, 0, ParameterDirection.InputOutput);
var command = provider.GetReadCommand(element, new EntityParameters
diff --git a/src/MasterData.Commons/Extensions/DictionaryExtensions.cs b/src/MasterData.Commons/Extensions/DictionaryExtensions.cs
deleted file mode 100644
index e8c93112c..000000000
--- a/src/MasterData.Commons/Extensions/DictionaryExtensions.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-#if !NET
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-
-namespace JJMasterData.Commons.Extensions;
-
-internal static class DictionaryExtensions
-{
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static TValue GetValueOrDefault(this IDictionary dictionary, TKey key, TValue defaultValue)
- {
- return dictionary.TryGetValue(key, out var value) ? value : defaultValue;
- }
-}
-#endif
\ No newline at end of file
diff --git a/src/MasterData.Commons/MasterData.Commons.csproj b/src/MasterData.Commons/MasterData.Commons.csproj
index b0e93038e..da657e4fc 100644
--- a/src/MasterData.Commons/MasterData.Commons.csproj
+++ b/src/MasterData.Commons/MasterData.Commons.csproj
@@ -1,6 +1,6 @@
- net4.8;net10.0
+ net10.0
latest
disable
JJMasterData.Commons - Sun Version
@@ -13,6 +13,7 @@
+
@@ -21,23 +22,13 @@
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
+
@@ -45,4 +36,7 @@
DataAccess.cs
+
+
+
diff --git a/src/MasterData.Commons/Resources/MasterDataResources.pt.resx b/src/MasterData.Commons/Resources/MasterDataResources.pt.resx
index 5bc80a9f0..880057091 100644
--- a/src/MasterData.Commons/Resources/MasterDataResources.pt.resx
+++ b/src/MasterData.Commons/Resources/MasterDataResources.pt.resx
@@ -190,6 +190,10 @@
Este campo oferece suporte a valores do runtime entre {}. Use {AppPath} para o caminho da raiz da aplicação.
JJMasterDataWeb
+
+
+ Este campo oferece suporte a valores do runtime entre {}.
+ JJMasterDataWeb
É Modal?
@@ -436,6 +440,10 @@
Limpar Filtro
JJMasterDataCore
+
+
+ Limpar Filtros
+ JJMasterDataCore
Limpar Log
@@ -1736,6 +1744,9 @@
Tipo de lista
JJMasterDataWeb
+
+
+ Coluna da Chave
Coluna da Chave Primária
@@ -2605,6 +2616,52 @@
Sincronizar
JJMasterData.Commons
+
+ Validações
+ JJMasterData.Commons
+
+
+ Regras
+
+
+ Tipo de validação
+
+
+ Tipo de regra
+
+
+ Ler mais
+
+
+ Executa antes do insert
+
+
+ Executa antes do update
+
+
+ Executa antes do delete
+
+
+ Tem certeza que deseja deletar esta regra?
+
+
+ Selecione pelo menos uma operação.
+
+
+ As regras em JavaScript rodam no servidor com Jint. Use addError(message) para um erro geral ou addError(name, message) para um erro de campo.
+
+
+ Antes de inserir e atualizar
+
+
+ Retorne uma coluna com a mensagem de erro ou duas colunas com campo e mensagem. Os nomes das colunas não importam.
+
+
+ Já existe uma validação com esse nome.
+
+
+ Já existe uma regra com esse nome.
+
Modo do Sincronismo
JJMasterDataWeb
@@ -3697,9 +3754,6 @@
Quando o painel está no modo visualuização, mostra apenas os valores sem os componentes.
-
- Valida valores potencialmente perigosos na requisição no .NET Framework 4.8
-
Tamanho do campo. Utilize -1 para utilizar a keyword MAX.
@@ -3901,9 +3955,6 @@
Ação de Exportação
-
- Mostrar Upload Fora do Modal
-
Campo [Nome] não pode começar com número
@@ -4224,6 +4275,10 @@
Abrir em uma Nova Aba
JJMasterDataWeb
+
+ Assinar Parâmetros com HMAC
+ JJMasterDataWeb
+
Deseja recriar a procedure de leitura? Quaisquer modificações feitas na procedure serão perdidas.
diff --git a/src/MasterData.Commons/Security/Cryptography/Abstractions/IEncryptionAlgorithm.cs b/src/MasterData.Commons/Security/Cryptography/Abstractions/IEncryptionAlgorithm.cs
deleted file mode 100644
index 8df48769a..000000000
--- a/src/MasterData.Commons/Security/Cryptography/Abstractions/IEncryptionAlgorithm.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace JJMasterData.Commons.Security.Cryptography.Abstractions;
-
-///
-/// Represents a secure encryption algorithm.
-///
-public interface IEncryptionAlgorithm
-{
- public string EncryptString(string plainText, string secretKey);
- public string DecryptString(string cipherText, string secretKey);
-}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Security/Cryptography/Abstractions/IEncryptionService.cs b/src/MasterData.Commons/Security/Cryptography/Abstractions/IEncryptionService.cs
index 9db595f62..4de897889 100644
--- a/src/MasterData.Commons/Security/Cryptography/Abstractions/IEncryptionService.cs
+++ b/src/MasterData.Commons/Security/Cryptography/Abstractions/IEncryptionService.cs
@@ -3,6 +3,6 @@ namespace JJMasterData.Commons.Security.Cryptography.Abstractions;
public interface IEncryptionService
{
- string EncryptString(string plainText, string? secretKey = null);
- string DecryptString(string cipherText, string? secretKey = null);
+ string EncryptString(string plainText);
+ string DecryptString(string cipherText);
}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Security/Cryptography/AesEncryptionAlgorithm.cs b/src/MasterData.Commons/Security/Cryptography/AesEncryptionAlgorithm.cs
deleted file mode 100644
index cf5527bbb..000000000
--- a/src/MasterData.Commons/Security/Cryptography/AesEncryptionAlgorithm.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-#nullable enable
-
-using System;
-using System.Collections.Concurrent;
-using System.IO;
-using System.Security.Cryptography;
-using System.Text;
-using JetBrains.Annotations;
-using JJMasterData.Commons.Security.Cryptography.Abstractions;
-
-namespace JJMasterData.Commons.Security.Cryptography;
-
-///
-/// AES is more secure than the DES cipher and is the de facto world standard. DES can be broken easily as it has known vulnerabilities.
-///
-public sealed class AesEncryptionAlgorithm : IEncryptionAlgorithm
-{
- private readonly ConcurrentDictionary _aesCache = new();
-
- public string EncryptString(string plainText, string secretKey)
- {
- using var aes = CreateAes(secretKey);
-
- using var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
-
- using var memoryStream = new MemoryStream();
- using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
- using (var streamWriter = new StreamWriter(cryptoStream))
- {
- streamWriter.Write(plainText);
- }
-
- return Convert.ToBase64String(memoryStream.ToArray());
- }
-
- public string DecryptString(string cipherText, string secretKey)
- {
- try
- {
- using var aes = CreateAes(secretKey);
- var buffer = Convert.FromBase64String(cipherText);
- using var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
-
- using var memoryStream = new MemoryStream(buffer);
- using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
- using var streamReader = new StreamReader(cryptoStream);
-
- return streamReader.ReadToEnd();
- }
- catch
- {
- return string.Empty;
- }
- }
-
- [MustDisposeResource]
- private Aes CreateAes(string secretKey)
- {
- if (_aesCache.TryGetValue(secretKey, out var aesEntry))
- {
- return CreateAes(aesEntry.Key, aesEntry.IV);
- }
-
- var keyBytes = Encoding.UTF8.GetBytes(secretKey);
-
- using var sha256 = SHA256.Create();
- var aesKey = sha256.ComputeHash(keyBytes);
-
- using var md5 = MD5.Create();
- var aesIv = md5.ComputeHash(keyBytes);
-
- aesEntry = new(aesKey, aesIv);
-
- _aesCache.TryAdd(secretKey, aesEntry);
-
- return CreateAes(aesEntry.Key, aesEntry.IV);
- }
-
- [MustDisposeResource]
- private static Aes CreateAes(byte[] key, byte[] iv)
- {
- var aes = Aes.Create();
- aes.Key = key;
- aes.IV = iv;
- return aes;
- }
-}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Security/Cryptography/DesEncryptionAlgorithm.cs b/src/MasterData.Commons/Security/Cryptography/DesEncryptionAlgorithm.cs
deleted file mode 100644
index 4eaadbdd2..000000000
--- a/src/MasterData.Commons/Security/Cryptography/DesEncryptionAlgorithm.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System;
-using System.IO;
-using System.Security.Cryptography;
-using System.Text;
-using JJMasterData.Commons.Security.Cryptography.Abstractions;
-
-namespace JJMasterData.Commons.Security.Cryptography;
-
-///
-/// DES algorithm can be broken easily as it has known vulnerabilities. Please use AesEncryptionService.
-///
-public class DesEncryptionAlgorithm : IEncryptionAlgorithm
-{
- private static readonly byte[] Iv = [12, 34, 56, 78, 90, 102, 114, 126];
-
- public string EncryptString(string plainText, string secretKey)
- {
- using var des = DES.Create();
- byte[] input = Encoding.UTF8.GetBytes(plainText);
- byte[] keyBytes = Encoding.UTF8.GetBytes(secretKey[..8]);
- using var ms = new MemoryStream();
- using (var cs = new CryptoStream(ms, des.CreateEncryptor(keyBytes, Iv), CryptoStreamMode.Write))
- {
- cs.Write(input, 0, input.Length);
- cs.FlushFinalBlock();
- }
- return Convert.ToBase64String(ms.ToArray());
- }
-
- public string DecryptString(string cipherText, string secretKey)
- {
- if (cipherText == null)
- return null;
- try
- {
- using var des = DES.Create();
- using var ms = new MemoryStream();
- var input = Convert.FromBase64String(cipherText.Replace(" ", "+"));
- var keyBytes = Encoding.UTF8.GetBytes(secretKey.Substring(0, 8));
- using (var cs = new CryptoStream(ms, des.CreateDecryptor(keyBytes, Iv), CryptoStreamMode.Write))
- {
- cs.Write(input, 0, input.Length);
- cs.FlushFinalBlock();
- }
-
- return Encoding.UTF8.GetString(ms.ToArray());
- }
- catch
- {
- return null;
- }
-
- }
-}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Security/Cryptography/EncryptionService.cs b/src/MasterData.Commons/Security/Cryptography/EncryptionService.cs
index a1c4ee3c9..b34b8857d 100644
--- a/src/MasterData.Commons/Security/Cryptography/EncryptionService.cs
+++ b/src/MasterData.Commons/Security/Cryptography/EncryptionService.cs
@@ -1,27 +1,35 @@
#nullable enable
-using JJMasterData.Commons.Configuration.Options;
+
+using System;
using JJMasterData.Commons.Security.Cryptography.Abstractions;
-using Microsoft.Extensions.Options;
+using Microsoft.AspNetCore.DataProtection;
namespace JJMasterData.Commons.Security.Cryptography;
-///
-/// Wrapper to IEncryptionService with the secret key loaded by IOptions.
-///
-public class EncryptionService(
- IEncryptionAlgorithm encryptionAlgorithm,
- IOptionsSnapshot options)
- : IEncryptionService
+internal sealed class EncryptionService : IEncryptionService
{
- private readonly string _secretKey = options.Value.SecretKey!;
+ private const string Purpose = "JJMasterData.Commons.Security.Cryptography.EncryptionService";
+
+ private readonly IDataProtector _protector;
+
+ public EncryptionService(IDataProtectionProvider dataProtectionProvider)
+ {
+ ArgumentNullException.ThrowIfNull(dataProtectionProvider);
- public string EncryptString(string plainText, string? secretKey = null)
+ _protector = dataProtectionProvider.CreateProtector(Purpose);
+ }
+
+ public string EncryptString(string plainText)
{
- return encryptionAlgorithm.EncryptString(plainText,secretKey ??_secretKey);
+ ArgumentNullException.ThrowIfNull(plainText);
+
+ return _protector.Protect(plainText);
}
- public string DecryptString(string cipherText, string? secretKey = null)
+ public string DecryptString(string cipherText)
{
- return encryptionAlgorithm.DecryptString(cipherText,secretKey ?? _secretKey);
+ ArgumentNullException.ThrowIfNull(cipherText);
+
+ return _protector.Unprotect(cipherText);
}
}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Security/Hashing/Md5HashHelper.cs b/src/MasterData.Commons/Security/Hashing/Md5HashHelper.cs
index 71017efee..d0e687585 100644
--- a/src/MasterData.Commons/Security/Hashing/Md5HashHelper.cs
+++ b/src/MasterData.Commons/Security/Hashing/Md5HashHelper.cs
@@ -8,12 +8,8 @@ public static class Md5HashHelper
{
public static string ComputeHash(string input)
{
- byte[] data;
- using (var md5Hasher = MD5.Create())
- {
- data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
- }
-
+ var data = MD5.HashData(Encoding.Default.GetBytes(input));
+
var stringBuilder = new StringBuilder();
for (var i = 0; i <= data.Length - 1; i++)
{
@@ -22,7 +18,7 @@ public static string ComputeHash(string input)
return stringBuilder.ToString();
}
-
+
public static bool VerifyHash(string input, string hash)
{
var hashOfInput = ComputeHash(input);
diff --git a/src/MasterData.Commons/Security/HmacHelper.cs b/src/MasterData.Commons/Security/HmacHelper.cs
new file mode 100644
index 000000000..3b4f1d6e7
--- /dev/null
+++ b/src/MasterData.Commons/Security/HmacHelper.cs
@@ -0,0 +1,120 @@
+#nullable enable
+using System;
+using System.Globalization;
+using System.Security.Cryptography;
+using System.Text;
+using Microsoft.Extensions.Options;
+
+namespace JJMasterData.Commons.Security;
+
+public class HmacHelper
+{
+ private readonly byte[] _key;
+ private readonly TimeSpan _clockSkew;
+
+ public HmacHelper(IOptions options)
+ {
+ var opt = options.Value;
+
+ _key = Encoding.UTF8.GetBytes(opt.SecretKey ?? string.Empty);
+ _clockSkew = opt.ClockSkew;
+ }
+
+ public string Generate(string content, DateTime? expiresUtc = null)
+ {
+ var contentBytes = Encoding.UTF8.GetBytes(content);
+
+ var ticks = expiresUtc?.ToUniversalTime().Ticks;
+
+ var data = ticks.HasValue
+ ? Combine(contentBytes, BitConverter.GetBytes(ticks.Value))
+ : contentBytes;
+
+ using var hmac = new HMACSHA256(_key);
+ var fullSig = hmac.ComputeHash(data);
+
+ var truncated = fullSig[..16];
+
+ var signature = Base64Url(truncated);
+
+ return ticks.HasValue
+ ? $"{signature}.{ticks.Value}"
+ : signature;
+ }
+
+ public bool Validate(string content, string token)
+ {
+ if (string.IsNullOrWhiteSpace(token))
+ return false;
+
+ var parts = token.Split('.');
+
+ var signaturePart = parts[0];
+ long? ticks = parts.Length > 1 ? long.Parse(parts[1]) : null;
+
+ if (ticks.HasValue)
+ {
+ var now = DateTime.UtcNow.Ticks;
+ if (now > ticks.Value + _clockSkew.Ticks)
+ return false;
+ }
+
+ var contentBytes = Encoding.UTF8.GetBytes(content);
+
+ var data = ticks.HasValue
+ ? Combine(contentBytes, BitConverter.GetBytes(ticks.Value))
+ : contentBytes;
+
+ using var hmac = new HMACSHA256(_key);
+ var expectedFull = hmac.ComputeHash(data);
+ var expected = expectedFull[..16];
+
+ var provided = Base64UrlDecode(signaturePart);
+
+ return CryptographicOperations.FixedTimeEquals(expected, provided);
+ }
+
+ private static byte[] Combine(byte[] a, byte[] b)
+ {
+ var result = new byte[a.Length + b.Length];
+ Buffer.BlockCopy(a, 0, result, 0, a.Length);
+ Buffer.BlockCopy(b, 0, result, a.Length, b.Length);
+ return result;
+ }
+
+ private static string Base64Url(byte[] input) =>
+ Convert.ToBase64String(input)
+ .Replace('+', '-')
+ .Replace('/', '_')
+ .TrimEnd('=');
+
+ private static byte[] Base64UrlDecode(string input)
+ {
+ var padded = input
+ .Replace('-', '+')
+ .Replace('_', '/');
+
+ padded = padded.PadRight(padded.Length + (4 - padded.Length % 4) % 4, '=');
+
+ return Convert.FromBase64String(padded);
+ }
+
+ public static DateTime? ParseExpirationUtc(string? expirationValue)
+ {
+ if (string.IsNullOrWhiteSpace(expirationValue)) return null;
+ if (long.TryParse(expirationValue, out var ticks)) return new DateTime(ticks, DateTimeKind.Utc);
+ if (DateTimeOffset.TryParse(expirationValue, CultureInfo.InvariantCulture,
+ DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var expirationOffset))
+ {
+ return expirationOffset.UtcDateTime;
+ }
+
+ if (DateTime.TryParse(expirationValue, CultureInfo.InvariantCulture,
+ DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var expirationDateTime))
+ {
+ return expirationDateTime.ToUniversalTime();
+ }
+
+ throw new ArgumentException("Invalid HMAC expiration. Use UTC date/time or ticks.");
+ }
+}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Security/HmacOptions.cs b/src/MasterData.Commons/Security/HmacOptions.cs
new file mode 100644
index 000000000..301a67bc3
--- /dev/null
+++ b/src/MasterData.Commons/Security/HmacOptions.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace JJMasterData.Commons.Security;
+
+public class HmacOptions
+{
+ public string SecretKey { get; set; } = string.Empty;
+ public TimeSpan ClockSkew { get; set; } = TimeSpan.FromMinutes(5);
+}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Storage/DiskFileStorage.cs b/src/MasterData.Commons/Storage/DiskFileStorage.cs
new file mode 100644
index 000000000..391f209cb
--- /dev/null
+++ b/src/MasterData.Commons/Storage/DiskFileStorage.cs
@@ -0,0 +1,94 @@
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using JJConsulting.MasterData.Storage.Abstractions;
+
+namespace JJMasterData.Commons.Storage;
+
+internal sealed class DiskFileStorage : IFileStorage
+{
+ public async Task SaveAsync(string fullPath, Stream content, bool replaceIfExists = true, CancellationToken cancellationToken = default)
+ {
+ var filePath = FileStoragePath.ResolveFullPath(fullPath);
+
+ var folderPath = Path.GetDirectoryName(filePath);
+ if (!string.IsNullOrEmpty(folderPath))
+ Directory.CreateDirectory(folderPath);
+
+ var mode = replaceIfExists ? FileMode.Create : FileMode.CreateNew;
+
+ if (content.CanSeek)
+ content.Seek(0, SeekOrigin.Begin);
+
+ await using var fileStream = new FileStream(filePath, mode, FileAccess.Write, FileShare.None, 81920, true);
+ await content.CopyToAsync(fileStream, cancellationToken);
+ }
+
+ public Task OpenReadAsync(string fullPath, CancellationToken cancellationToken = default)
+ {
+ var filePath = FileStoragePath.ResolveFullPath(fullPath);
+ Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 81920, true);
+ return Task.FromResult(stream);
+ }
+
+ public Task DeleteAsync(string fullPath, CancellationToken cancellationToken = default)
+ {
+ var filePath = FileStoragePath.ResolveFullPath(fullPath);
+ if (File.Exists(filePath))
+ File.Delete(filePath);
+ else
+ throw new KeyNotFoundException("File not found");
+
+ return Task.CompletedTask;
+ }
+
+ public Task DeleteFolderAsync(string folderPath, CancellationToken cancellationToken = default)
+ {
+ var resolvedFolderPath = FileStoragePath.ResolveFolderPath(folderPath);
+ if (Directory.Exists(resolvedFolderPath))
+ Directory.Delete(resolvedFolderPath, true);
+
+ return Task.CompletedTask;
+ }
+
+ public Task MoveAsync(string currentFullPath, string newFullPath, CancellationToken cancellationToken = default)
+ {
+ var currentPath = FileStoragePath.ResolveFullPath(currentFullPath);
+ var newPath = FileStoragePath.ResolveFullPath(newFullPath);
+
+ if (!File.Exists(currentPath))
+ throw new KeyNotFoundException("File not found");
+
+ var newFolderPath = Path.GetDirectoryName(newPath);
+ if (!string.IsNullOrEmpty(newFolderPath))
+ Directory.CreateDirectory(newFolderPath);
+
+ File.Move(currentPath, newPath, true);
+
+ return Task.CompletedTask;
+ }
+
+ public Task> ListAsync(string folderPath, bool isRecursive = false, CancellationToken cancellationToken = default)
+ {
+ var resolvedFolderPath = FileStoragePath.ResolveFolderPath(folderPath);
+ if (!Directory.Exists(resolvedFolderPath))
+ return Task.FromResult(new List());
+
+ var searchOption = isRecursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
+ var files = new DirectoryInfo(resolvedFolderPath)
+ .EnumerateFiles("*", searchOption)
+ .Select(file => new FileStorageItem
+ {
+ FileName = file.Name,
+ Length = file.Length,
+ LastWriteTime = file.LastWriteTime,
+ FolderPath = folderPath
+ })
+ .ToList();
+
+ return Task.FromResult(files);
+ }
+}
diff --git a/src/MasterData.Commons/Storage/FileStorageItemExtensions.cs b/src/MasterData.Commons/Storage/FileStorageItemExtensions.cs
new file mode 100644
index 000000000..f27d179fc
--- /dev/null
+++ b/src/MasterData.Commons/Storage/FileStorageItemExtensions.cs
@@ -0,0 +1,20 @@
+using JJConsulting.MasterData.Storage.Abstractions;
+
+namespace JJMasterData.Commons.Storage;
+
+public static class FileStorageItemExtensions
+{
+ extension(FileStorageItem item)
+ {
+ public string FullPath
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(item.FolderPath))
+ return FileStoragePath.GetFileName(item.FileName);
+
+ return FileStoragePath.Combine(item.FolderPath, item.FileName);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Storage/FileStoragePath.cs b/src/MasterData.Commons/Storage/FileStoragePath.cs
new file mode 100644
index 000000000..60602217a
--- /dev/null
+++ b/src/MasterData.Commons/Storage/FileStoragePath.cs
@@ -0,0 +1,53 @@
+using System;
+using System.IO;
+using JJMasterData.Commons.Util;
+
+namespace JJMasterData.Commons.Storage;
+
+public static class FileStoragePath
+{
+ public static string Combine(string folderPath, string fileName)
+ {
+ var safeFileName = GetFileName(fileName);
+
+ return string.IsNullOrEmpty(folderPath)
+ ? safeFileName
+ : $"{folderPath.TrimEnd('/', '\\')}/{safeFileName}";
+ }
+
+ public static string GetFileName(string path)
+ {
+ return Path.GetFileName(path?.Replace('\\', '/') ?? string.Empty);
+ }
+
+ private static string GetFilePath(string folderPath, string fileName)
+ {
+ return Path.Combine(folderPath, GetFileName(fileName));
+ }
+
+ public static string ResolveFolderPath(string folderPath)
+ {
+ if (string.IsNullOrEmpty(folderPath))
+ throw new ArgumentNullException(nameof(folderPath));
+
+ var separator = Path.DirectorySeparatorChar;
+ var resolvedFolderPath = folderPath.Replace("{app.path}", FileIO.GetApplicationPath().TrimEnd(separator));
+
+ return Path.GetFullPath(resolvedFolderPath);
+ }
+
+ public static string ResolveFullPath(string fullPath)
+ {
+ if (string.IsNullOrEmpty(fullPath))
+ throw new ArgumentNullException(nameof(fullPath));
+
+ var normalizedFullPath = fullPath.Replace('\\', '/');
+ var folderPath = Path.GetDirectoryName(normalizedFullPath);
+ if (string.IsNullOrEmpty(folderPath))
+ throw new ArgumentException(@"File path must include a folder.", nameof(fullPath));
+
+ var resolvedFolderPath = ResolveFolderPath(folderPath);
+
+ return GetFilePath(resolvedFolderPath, GetFileName(normalizedFullPath));
+ }
+}
diff --git a/src/MasterData.Commons/Storage/StorageCollectionExtensions.cs b/src/MasterData.Commons/Storage/StorageCollectionExtensions.cs
new file mode 100644
index 000000000..f0c8a80ff
--- /dev/null
+++ b/src/MasterData.Commons/Storage/StorageCollectionExtensions.cs
@@ -0,0 +1,25 @@
+using System;
+using JJConsulting.MasterData.Storage.Abstractions;
+using JJMasterData.Commons.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace JJMasterData.Commons.Storage;
+
+public static class MasterDataServiceCollectionExtensions
+{
+ extension(MasterDataServiceBuilder builder)
+ {
+ public MasterDataServiceBuilder WithFileStorage(Func implementationFactory)
+ {
+ builder.Services.Replace(ServiceDescriptor.Transient(implementationFactory));
+ return builder;
+ }
+
+ public MasterDataServiceBuilder WithFileStorage() where T : IFileStorage
+ {
+ builder.Services.Replace(ServiceDescriptor.Transient(typeof(IFileStorage),typeof(T)));
+ return builder;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MasterData.Commons/Util/CountryHelper.cs b/src/MasterData.Commons/Util/CountryHelper.cs
index 0b504b0fb..02d9ff78f 100644
--- a/src/MasterData.Commons/Util/CountryHelper.cs
+++ b/src/MasterData.Commons/Util/CountryHelper.cs
@@ -4,7 +4,7 @@
using System.Collections.ObjectModel;
using System.Linq;
-namespace JJMasterData.Core.DataDictionary.Services;
+namespace JJMasterData.Commons.Util;
public enum CountryCode
{
diff --git a/src/MasterData.Commons/Util/DictionaryHash.cs b/src/MasterData.Commons/Util/DictionaryHash.cs
index e376786fc..e73a2d7c5 100644
--- a/src/MasterData.Commons/Util/DictionaryHash.cs
+++ b/src/MasterData.Commons/Util/DictionaryHash.cs
@@ -13,14 +13,8 @@ public static string ComputeHash(Dictionary dict)
{
var ordered = dict.OrderBy(x => x.Key);
var json = JsonSerializer.Serialize(ordered);
-
- using var sha = SHA256.Create();
- var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(json));
-
- #if NETFRAMEWORK
- return BitConverter.ToString(bytes).Replace("-", "");
- #else
+ var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(json));
+
return Convert.ToHexString(bytes);
- #endif
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Commons/Util/FileIO.cs b/src/MasterData.Commons/Util/FileIO.cs
index b2f6d44f9..ee799e177 100644
--- a/src/MasterData.Commons/Util/FileIO.cs
+++ b/src/MasterData.Commons/Util/FileIO.cs
@@ -2,8 +2,6 @@
using System.Data;
using System.Globalization;
using System.IO;
-using JJMasterData.Commons.Configuration.Options;
-
namespace JJMasterData.Commons.Util;
public static class FileIO
@@ -50,13 +48,11 @@ public static string ResolveFilePath(string filepath)
///
/// Returns the application path.
- /// .NET Framework: AppDomain.CurrentDomain.BaseDirectory
- /// ..NET 8+: Environment.CurrentDirectory
///
///
public static string GetApplicationPath()
{
- return MasterDataCommonsOptions.IsNetFramework ? AppDomain.CurrentDomain.BaseDirectory : Environment.CurrentDirectory;
+ return Environment.CurrentDirectory;
}
///
diff --git a/src/MasterData.Commons/Util/MimeTypeUtil.cs b/src/MasterData.Commons/Util/MimeTypeUtil.cs
index 929f617c4..e5a807bad 100644
--- a/src/MasterData.Commons/Util/MimeTypeUtil.cs
+++ b/src/MasterData.Commons/Util/MimeTypeUtil.cs
@@ -2,10 +2,6 @@
using System.Collections.Frozen;
using System.Collections.Generic;
-#if NET48
-using JJMasterData.Commons.Extensions;
-#endif
-
namespace JJMasterData.Commons.Util;
public static class MimeTypeUtil
@@ -248,6 +244,7 @@ public static class MimeTypeUtil
{".manifest", "application/x-ms-manifest"},
{".map", "text/plain"},
{".master", "application/xml"},
+ {".md", "text/markdown"},
{".mda", "application/msaccess"},
{".mdb", "application/x-msaccess"},
{".mde", "application/msaccess"},
@@ -596,4 +593,4 @@ public static string GetMimeType(string extension)
return Mappings.GetValueOrDefault(extension, "application/octet-stream");
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Commons/Util/StringManager.cs b/src/MasterData.Commons/Util/StringManager.cs
index ff7fa91b7..9223e690b 100644
--- a/src/MasterData.Commons/Util/StringManager.cs
+++ b/src/MasterData.Commons/Util/StringManager.cs
@@ -462,21 +462,12 @@ private static string Soma1(string baseVal, int size)
public static string FirstCharToUpper(this string input)
{
- //Since .NET Core 3.0 / .NET Standard 2.1 String.Concat()
- //supports ReadonlySpan which saves one allocation if we use .AsSpan(1) instead of .Substring(1).
-#if NET
return input switch
{
null => throw new ArgumentNullException(nameof(input)),
"" => throw new ArgumentException(@$"{nameof(input)} cannot be empty", nameof(input)),
_ => string.Concat(input[0].ToString().ToUpper(), input.AsSpan(1))
};
-#else
- if (!string.IsNullOrEmpty(input))
- return input[0].ToString().ToUpper() + input[1..].ToLower();
- return input;
-#endif
-
}
public static string ToParamCase(string input)
diff --git a/src/MasterData.Commons/Validations/Validations.cs b/src/MasterData.Commons/Validations/Validations.cs
index ad30cdfd2..5699af66e 100644
--- a/src/MasterData.Commons/Validations/Validations.cs
+++ b/src/MasterData.Commons/Validations/Validations.cs
@@ -23,7 +23,7 @@ public static bool ValidateCnpj(string cnpj)
/// E-Mail
public static bool ValidateEmail(string email)
{
- if (email.Contains("'"))
+ if (email.Contains('\''))
return false;
if (email.Contains('@') && email.Contains('.') && !email.Contains(".."))
diff --git a/src/MasterData.Core/Configuration/ActionsServiceExtensions.cs b/src/MasterData.Core/Configuration/ActionsServiceExtensions.cs
index 8153bcacb..b7a8570db 100644
--- a/src/MasterData.Core/Configuration/ActionsServiceExtensions.cs
+++ b/src/MasterData.Core/Configuration/ActionsServiceExtensions.cs
@@ -15,7 +15,7 @@ public static IServiceCollection AddActionServices(this IServiceCollection servi
AllowParentheses = true
}));
- services.AddScoped();
+ services.AddScoped();
services.AddScoped();
return services;
}
diff --git a/src/MasterData.Core/Configuration/DataDictionaryServiceExtensions.cs b/src/MasterData.Core/Configuration/DataDictionaryServiceExtensions.cs
index 766880d2f..04c4c0736 100644
--- a/src/MasterData.Core/Configuration/DataDictionaryServiceExtensions.cs
+++ b/src/MasterData.Core/Configuration/DataDictionaryServiceExtensions.cs
@@ -20,6 +20,7 @@ public static IServiceCollection AddDataDictionaryServices(this IServiceCollecti
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
services.AddTransient();
return services;
diff --git a/src/MasterData.Core/Configuration/DataManagerServiceExtensions.cs b/src/MasterData.Core/Configuration/DataManagerServiceExtensions.cs
index 3afeefef7..d1a0fbcb4 100644
--- a/src/MasterData.Core/Configuration/DataManagerServiceExtensions.cs
+++ b/src/MasterData.Core/Configuration/DataManagerServiceExtensions.cs
@@ -1,7 +1,10 @@
+using JJMasterData.Commons.Storage;
using JJMasterData.Core.DataManager;
-using JJMasterData.Core.DataManager.IO;
using JJMasterData.Core.DataManager.Services;
+using JJMasterData.Core.DataManager.Services.Abstractions;
+using JJMasterData.Core.UI.Components;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
namespace JJMasterData.Core.Configuration;
@@ -9,24 +12,28 @@ public static class DataManagerServiceExtensions
{
public static IServiceCollection AddDataManagerServices(this IServiceCollection services)
{
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
-#if NET
- services.AddScoped();
-#endif
- services.AddScoped();
- services.AddScoped();
+ services.TryAddScoped();
+
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
+
+ services.TryAddEnumerable(ServiceDescriptor.Scoped());
+ services.TryAddEnumerable(ServiceDescriptor.Scoped());
+
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
+
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
+ services.TryAddTransient();
return services;
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/Configuration/FactoriesServiceExtensions.cs b/src/MasterData.Core/Configuration/FactoriesServiceExtensions.cs
index bf31fb3c4..93eb634f5 100644
--- a/src/MasterData.Core/Configuration/FactoriesServiceExtensions.cs
+++ b/src/MasterData.Core/Configuration/FactoriesServiceExtensions.cs
@@ -1,4 +1,3 @@
-using JJConsulting.Html.Bootstrap.Components;
using JJMasterData.Core.DataDictionary.Structure;
using JJMasterData.Core.DataManager.Exportation;
using JJMasterData.Core.DataManager.Importation;
diff --git a/src/MasterData.Core/Configuration/HttpServiceExtensions.cs b/src/MasterData.Core/Configuration/HttpServiceExtensions.cs
index 036190000..2a1367ff5 100644
--- a/src/MasterData.Core/Configuration/HttpServiceExtensions.cs
+++ b/src/MasterData.Core/Configuration/HttpServiceExtensions.cs
@@ -1,10 +1,6 @@
-using JJMasterData.Core.Http;
-using JJMasterData.Core.Http.Abstractions;
-using Microsoft.Extensions.DependencyInjection;
-#if NET
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
-#endif
+using Microsoft.Extensions.DependencyInjection;
namespace JJMasterData.Core.Configuration;
@@ -12,16 +8,7 @@ public static class HttpServiceExtensions
{
public static void AddHttpServices(this IServiceCollection services)
{
- services.AddScoped();
-#if NET
services.AddHttpContextAccessor();
- services.AddScoped();
-
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
#pragma warning disable ASPDEPR006
services.AddSingleton();
@@ -33,19 +20,5 @@ public static void AddHttpServices(this IServiceCollection services)
var urlHelperFactory = serviceProvider.GetRequiredService();
return urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext!);
});
-#endif
-
-
-#if NETFRAMEWORK
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
-#endif
-
-
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/Configuration/MasterDataServiceBuilderExtensions.cs b/src/MasterData.Core/Configuration/MasterDataServiceBuilderExtensions.cs
index 0158b56c7..393e57910 100644
--- a/src/MasterData.Core/Configuration/MasterDataServiceBuilderExtensions.cs
+++ b/src/MasterData.Core/Configuration/MasterDataServiceBuilderExtensions.cs
@@ -1,7 +1,4 @@
-#nullable enable
-
-using System;
-using System.Reflection;
+using System;
using JJMasterData.Commons.Configuration;
using JJMasterData.Commons.Data;
using JJMasterData.Commons.Data.Entity.Repository.Abstractions;
diff --git a/src/MasterData.Core/Configuration/Options/MasterDataCoreOptions.cs b/src/MasterData.Core/Configuration/Options/MasterDataCoreOptions.cs
index 44a8b28a3..e2568c6bd 100644
--- a/src/MasterData.Core/Configuration/Options/MasterDataCoreOptions.cs
+++ b/src/MasterData.Core/Configuration/Options/MasterDataCoreOptions.cs
@@ -1,10 +1,6 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
-using System.IO;
-using System.Linq;
using System.Security.Claims;
using JJMasterData.Commons.Util;
using NCalc;
@@ -33,37 +29,37 @@ public sealed class MasterDataCoreOptions
[Display(Name = "Audit Log Table Name")]
public string AuditLogTableName { get; set; } = "tb_masterdata_auditlog";
-#if !NET
- ///
- /// Default value: null
- ///
- public string? MasterDataUrl { get; set; }
-
- public bool EnableCultureProviderAtUrl { get; set; } = true;
-#endif
-
[Display(Name = "Enable Data Dictionary Caching")]
public bool EnableDataDictionaryCaching { get; set; } = true;
///
- /// Default value: {ApplicationPath}/JJExportationFiles
+ /// Default value: {app.path}/JJExportationFiles
///
[Display(Name = "Exportation Folder Path")]
- public string ExportationFolderPath { get; set; } = Path.Combine(FileIO.GetApplicationPath(), "JJExportationFiles");
+ public string ExportationFolderPath { get; set; } = "{app.path}/JJExportationFiles";
public string UserIdClaimType { get; set; } = ClaimTypes.NameIdentifier;
+ ///
+ /// Configuration of expression
+ ///
+ public ExpressionConfiguration ExpressionConfiguration { get; set; } = new()
+ {
+ Evaluation = new ExpressionEvaluationOptions
+ {
+ AllowNullParameter = true,
+ AllowNullOrEmptyExpressions = true,
+ IgnoreCaseAtBuiltInFunctions = true,
+ ArithmeticNullOrEmptyStringAsZero = true,
+ StringComparer = StringComparer.OrdinalIgnoreCase,
+ }
+ };
+
///
/// Context of expressions starting with "exp:". Declare here custom parameters and functions.
///
public ExpressionContext ExpressionContext { get; set; } = new()
{
- Options = ExpressionOptions.IgnoreCaseAtBuiltInFunctions
- | ExpressionOptions.AllowNullParameter
- | ExpressionOptions.OrdinalStringComparer
- | ExpressionOptions.AllowNullOrEmptyExpressions
- | ExpressionOptions.ArithmeticNullOrEmptyStringAsZero
- | ExpressionOptions.CaseInsensitiveStringComparer,
Functions = new Dictionary(StringComparer.InvariantCultureIgnoreCase)
{
{
@@ -78,7 +74,7 @@ public sealed class MasterDataCoreOptions
{
"iif", args =>
{
- if (args.Count() != 3)
+ if (args.Count != 3)
throw new NCalcEvaluationException("iif() takes exactly 3 arguments.");
var conditional = StringManager.ParseBool(args.Evaluate(0));
return conditional ? args.Evaluate(1) : args.Evaluate(2);
@@ -87,7 +83,7 @@ public sealed class MasterDataCoreOptions
{
"len", args =>
{
- if (args.Count() != 1)
+ if (args.Count != 1)
{
throw new NCalcEvaluationException("len() takes exactly 1 argument.");
}
@@ -105,7 +101,29 @@ public sealed class MasterDataCoreOptions
return args.Evaluate(0)?.ToString()?.Trim();
}
+ },
+ {
+ "coalesce", args =>
+ {
+ if (args.Count == 0)
+ throw new NCalcEvaluationException("coalesce() takes at least 1 argument.");
+
+ for (var i = 0; i < args.Count; i++)
+ {
+ var value = args.Evaluate(i);
+
+ if (value == null)
+ continue;
+
+ if (value is string str && string.IsNullOrEmpty(str))
+ continue;
+
+ return value;
+ }
+
+ return null;
+ }
}
}
};
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/Configuration/Options/MasterDataCoreOptionsConfiguration.cs b/src/MasterData.Core/Configuration/Options/MasterDataCoreOptionsConfiguration.cs
index 97cc9dee3..950b68d98 100644
--- a/src/MasterData.Core/Configuration/Options/MasterDataCoreOptionsConfiguration.cs
+++ b/src/MasterData.Core/Configuration/Options/MasterDataCoreOptionsConfiguration.cs
@@ -1,5 +1,4 @@
-#nullable enable
-using System;
+using System;
using JJMasterData.Commons.Configuration.Options;
namespace JJMasterData.Core.Configuration.Options;
diff --git a/src/MasterData.Core/Configuration/ServiceCollectionExtensions.cs b/src/MasterData.Core/Configuration/ServiceCollectionExtensions.cs
index 9d88a0ec5..43cfddcdd 100644
--- a/src/MasterData.Core/Configuration/ServiceCollectionExtensions.cs
+++ b/src/MasterData.Core/Configuration/ServiceCollectionExtensions.cs
@@ -4,7 +4,6 @@
using JJMasterData.Core.DataDictionary.Repository.Abstractions;
using JJMasterData.Core.DataManager.Exportation;
using JJMasterData.Core.DataManager.Exportation.Abstractions;
-using JJMasterData.Core.Html;
using JJMasterData.Core.Html.Templates;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -13,54 +12,53 @@ namespace JJMasterData.Core.Configuration;
public static class ServiceCollectionExtensions
{
- public static MasterDataServiceBuilder AddJJMasterDataCore(this IServiceCollection services)
+ extension(IServiceCollection services)
{
- services.AddMasterDataCoreServices();
+ public MasterDataServiceBuilder AddJJMasterDataCore()
+ {
+ services.AddMasterDataCoreServices();
- return services.AddJJMasterDataCommons();
- }
+ return services.AddJJMasterDataCommons();
+ }
- public static MasterDataServiceBuilder AddJJMasterDataCore(
- this IServiceCollection services,
- MasterDataCoreOptionsConfiguration optionsConfiguration
+ public MasterDataServiceBuilder AddJJMasterDataCore(MasterDataCoreOptionsConfiguration optionsConfiguration
)
- {
- if (optionsConfiguration.ConfigureCore != null)
- services.PostConfigure(optionsConfiguration.ConfigureCore);
+ {
+ if (optionsConfiguration.ConfigureCore != null)
+ services.PostConfigure(optionsConfiguration.ConfigureCore);
- services.AddMasterDataCoreServices();
- return services.AddJJMasterDataCommons(optionsConfiguration.ConfigureCommons);
- }
+ services.AddMasterDataCoreServices();
+ return services.AddJJMasterDataCommons(optionsConfiguration.ConfigureCommons);
+ }
- public static MasterDataServiceBuilder AddJJMasterDataCore(this IServiceCollection services,
- IConfiguration configuration)
- {
- services.Configure(configuration.GetJJMasterData());
+ public MasterDataServiceBuilder AddJJMasterDataCore(IConfiguration configuration)
+ {
+ services.Configure(configuration.GetJJMasterData());
- services.AddMasterDataCoreServices();
+ services.AddMasterDataCoreServices();
- return services.AddJJMasterDataCommons(configuration);
- }
+ return services.AddJJMasterDataCommons(configuration);
+ }
- private static void AddMasterDataCoreServices(this IServiceCollection services)
- {
- services.AddOptions().BindConfiguration("JJMasterData");
+ private void AddMasterDataCoreServices()
+ {
+ services.AddOptions().BindConfiguration("JJMasterData");
- services.AddHttpServices();
- services.AddDataDictionaryServices();
- services.AddDataManagerServices();
- services.AddEventHandlers();
- services.AddExpressionServices();
- services.AddActionServices();
+ services.AddHttpServices();
+ services.AddDataDictionaryServices();
+ services.AddDataManagerServices();
+ services.AddEventHandlers();
+ services.AddExpressionServices();
+ services.AddActionServices();
- services.AddScoped();
+ services.AddScoped();
- services.AddTransient();
- services.AddTransient();
+ services.AddTransient();
- services.AddScoped();
- services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
- services.AddFactories();
+ services.AddFactories();
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/BasicAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/BasicAction.cs
index 125123717..1f578d897 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/BasicAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/BasicAction.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/FormElementActionList.cs b/src/MasterData.Core/DataDictionary/Models/Actions/FormElementActionList.cs
index 34003ea74..6ff65900d 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/FormElementActionList.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/FormElementActionList.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections;
using System.Collections.Generic;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/BackAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/BackAction.cs
index 7be495ba0..1743f5e51 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/BackAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/BackAction.cs
@@ -1,6 +1,3 @@
-#nullable enable
-
-
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/CancelAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/CancelAction.cs
index 80792638e..0daa9ec03 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/CancelAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/CancelAction.cs
@@ -1,6 +1,3 @@
-#nullable enable
-
-
using JJConsulting.FontAwesome;
namespace JJMasterData.Core.DataDictionary.Models.Actions;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/SaveAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/SaveAction.cs
index 17be36dba..eb95a600e 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/SaveAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/FormToolbar/SaveAction.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/GridTable/EditAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/GridTable/EditAction.cs
index 62efdf785..5f07b2b15 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/GridTable/EditAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/GridTable/EditAction.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel.DataAnnotations;
+#nullable disable warnings
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/GridTable/ViewAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/GridTable/ViewAction.cs
index 1ad7dc9c3..96e400c40 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/GridTable/ViewAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/GridTable/ViewAction.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel.DataAnnotations;
+#nullable disable warnings
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/ExportAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/ExportAction.cs
index 8380ee6b7..1b5e3f783 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/ExportAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/ExportAction.cs
@@ -1,6 +1,4 @@
-
-#nullable enable
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/ImportAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/ImportAction.cs
index 323747108..7925e8eb4 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/ImportAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/ImportAction.cs
@@ -1,5 +1,4 @@
-#nullable enable
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/InsertAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/InsertAction.cs
index aa463d007..e29b73762 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/InsertAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/GridToolbar/InsertAction.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel.DataAnnotations;
+#nullable disable warnings
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
@@ -22,7 +23,7 @@ public sealed class InsertAction : GridToolbarAction, IModalAction
///
[JsonPropertyName("elementNameToSelect")]
[Display(Name = "Element Name To Select")]
- public string ElementNameToSelect { get; set; }
+ public string? ElementNameToSelect { get; set; }
///
/// Re-opens the insert after saving.
@@ -37,7 +38,7 @@ public sealed class InsertAction : GridToolbarAction, IModalAction
[Display(Name = "Modal Title")]
[JsonPropertyName("modalTitle")]
- public string ModalTitle { get; set; }
+ public string? ModalTitle { get; set; }
[Display(Name = "Success Message")]
[JsonPropertyName("successMessage")]
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/HtmlTemplateAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/HtmlTemplateAction.cs
index dc04e1dc5..5e46b20fa 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/HtmlTemplateAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/HtmlTemplateAction.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginActionHandler.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginActionHandler.cs
index c28f1cdfc..513112b81 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginActionHandler.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginActionHandler.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System.Threading.Tasks;
namespace JJMasterData.Core.DataDictionary.Models.Actions;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginFieldActionHandler.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginFieldActionHandler.cs
index 1c9a40285..20f9aed13 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginFieldActionHandler.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginFieldActionHandler.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System.Collections.Generic;
using System.Threading.Tasks;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginHandler.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginHandler.cs
index da5a19c8a..ef4e82a7a 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginHandler.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/IPluginHandler.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Collections.Generic;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginAction.cs
index 2fc870b79..9dc4df982 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginAction.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginActionContext.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginActionContext.cs
index 973dbaa69..d33b31812 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginActionContext.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginActionContext.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System.Collections.Generic;
namespace JJMasterData.Core.DataDictionary.Models.Actions;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginActionResult.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginActionResult.cs
index 8fcbd5af3..165b45f19 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginActionResult.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginActionResult.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using JJConsulting.Html.Bootstrap.Components;
using JJConsulting.Html.Bootstrap.Models;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginConfigurationField.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginConfigurationField.cs
index 5f5862d3c..41248ab7c 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginConfigurationField.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginConfigurationField.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
namespace JJMasterData.Core.DataDictionary.Models.Actions;
public class PluginConfigurationField
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginFieldAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginFieldAction.cs
index d546074c0..7e9c0c19c 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginFieldAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginFieldAction.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.Json.Serialization;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginFieldActionContext.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginFieldActionContext.cs
index ca6491d07..5510c345c 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginFieldActionContext.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Plugins/PluginFieldActionContext.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System.Collections.Generic;
namespace JJMasterData.Core.DataDictionary.Models.Actions;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/ScriptAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/ScriptAction.cs
index c0a466cf3..dfda372fd 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/ScriptAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/ScriptAction.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel.DataAnnotations;
+#nullable disable warnings
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JetBrains.Annotations;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/ActionListConverterBase.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/ActionListConverterBase.cs
index 53b6acad3..85aff56c3 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/ActionListConverterBase.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/ActionListConverterBase.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System;
using System.Collections.Generic;
using System.Text.Json;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/FormElementFieldActionListConverter.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/FormElementFieldActionListConverter.cs
index 37110c9d0..51d996883 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/FormElementFieldActionListConverter.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/FormElementFieldActionListConverter.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System.Text.Json;
namespace JJMasterData.Core.DataDictionary.Models.Actions;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/FormToolbarActionListConverter.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/FormToolbarActionListConverter.cs
index ca84a075e..99a34560f 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/FormToolbarActionListConverter.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/FormToolbarActionListConverter.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System.Text.Json;
namespace JJMasterData.Core.DataDictionary.Models.Actions;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/GridTableActionListConverter.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/GridTableActionListConverter.cs
index d1f1aec87..27f1faf87 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/GridTableActionListConverter.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/GridTableActionListConverter.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System.Text.Json;
namespace JJMasterData.Core.DataDictionary.Models.Actions;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/GridToolbarActionListConverter.cs b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/GridToolbarActionListConverter.cs
index 0500628dc..b3f0d14f6 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/GridToolbarActionListConverter.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/Serialization/GridToolbarActionListConverter.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System.Text.Json;
namespace JJMasterData.Core.DataDictionary.Models.Actions;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/SqlCommandAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/SqlCommandAction.cs
index 58dd2b76e..3eaba9036 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/SqlCommandAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/SqlCommandAction.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
diff --git a/src/MasterData.Core/DataDictionary/Models/Actions/UrlRedirectAction.cs b/src/MasterData.Core/DataDictionary/Models/Actions/UrlRedirectAction.cs
index 87f36baa5..681fc748d 100644
--- a/src/MasterData.Core/DataDictionary/Models/Actions/UrlRedirectAction.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Actions/UrlRedirectAction.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel.DataAnnotations;
+#nullable disable warnings
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
using JJConsulting.Html.Bootstrap.Models;
@@ -32,6 +33,10 @@ public sealed class UrlRedirectAction : BasicAction
[JsonPropertyName("encryptParameters")]
[Display(Name="Encrypt Parameters")]
public bool EncryptParameters { get; set; }
+
+ [JsonPropertyName("signParametersWithHmac")]
+ [Display(Name = "Sign Parameters with HMAC")]
+ public bool SignParametersWithHmac { get; set; }
[JsonPropertyName("openInNewTab")]
[Display(Name="Open in New Tab")]
@@ -45,4 +50,4 @@ public UrlRedirectAction()
public override bool IsUserDefined => true;
public override BasicAction DeepCopy() => (BasicAction)MemberwiseClone();
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataDictionary/Models/DataElementMap.cs b/src/MasterData.Core/DataDictionary/Models/DataElementMap.cs
index 4036b9fa0..9e8aeb5ad 100644
--- a/src/MasterData.Core/DataDictionary/Models/DataElementMap.cs
+++ b/src/MasterData.Core/DataDictionary/Models/DataElementMap.cs
@@ -1,5 +1,4 @@
-#nullable enable
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.Html.Bootstrap.Models;
diff --git a/src/MasterData.Core/DataDictionary/Models/DataElementMapFilter.cs b/src/MasterData.Core/DataDictionary/Models/DataElementMapFilter.cs
index 7e8f665ec..c41f293ec 100644
--- a/src/MasterData.Core/DataDictionary/Models/DataElementMapFilter.cs
+++ b/src/MasterData.Core/DataDictionary/Models/DataElementMapFilter.cs
@@ -1,6 +1,6 @@
-using System.ComponentModel.DataAnnotations;
+#nullable disable warnings
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
-using JJMasterData.Commons.Data.Entity.Models;
namespace JJMasterData.Core.DataDictionary.Models;
diff --git a/src/MasterData.Core/DataDictionary/Models/DataItemValue.cs b/src/MasterData.Core/DataDictionary/Models/DataItemValue.cs
index 305287214..fc9d0e948 100644
--- a/src/MasterData.Core/DataDictionary/Models/DataItemValue.cs
+++ b/src/MasterData.Core/DataDictionary/Models/DataItemValue.cs
@@ -1,8 +1,9 @@
-using System.Text.Json.Serialization;
+#nullable disable warnings
+using System.Diagnostics.CodeAnalysis;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JJConsulting.FontAwesome;
-
namespace JJMasterData.Core.DataDictionary.Models;
///
@@ -12,18 +13,17 @@ namespace JJMasterData.Core.DataDictionary.Models;
public class DataItemValue
{
[JsonPropertyName("id")]
- public string Id { get; set; }
+ public required string Id { get; set; }
[JsonPropertyName("description")]
- [CanBeNull]
- public string Description { get; set; }
+ public string? Description { get; set; }
[CanBeNull]
[JsonPropertyName("imageUrl")]
- public string ImageUrl { get; set; }
+ public string? ImageUrl { get; set; }
[JsonPropertyName("icon")]
- public FontAwesomeIcon Icon { get; set; }
+ public FontAwesomeIcon? Icon { get; set; }
///
/// Image color in hexadecimal.
@@ -32,19 +32,21 @@ public class DataItemValue
/// #FF112F1
///
[JsonPropertyName("imagecolor")]
- public string IconColor { get; set; }
+ public string? IconColor { get; set; }
- [JsonPropertyName("group")]
- [CanBeNull]
- public string Group { get; set; }
+ [JsonPropertyName("group")]
+ public string? Group { get; set; }
public DataItemValue() { }
+ [SetsRequiredMembers]
public DataItemValue(string id, string description)
{
Id = id;
Description = description;
}
+
+ [SetsRequiredMembers]
public DataItemValue(string id, string description, FontAwesomeIcon icon, string iconColor)
{
Id = id;
@@ -57,4 +59,4 @@ public DataItemValue DeepCopy()
{
return (DataItemValue)MemberwiseClone();
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataDictionary/Models/ElementBean.cs b/src/MasterData.Core/DataDictionary/Models/ElementBean.cs
index ef2b91fb4..e6e7c6b19 100644
--- a/src/MasterData.Core/DataDictionary/Models/ElementBean.cs
+++ b/src/MasterData.Core/DataDictionary/Models/ElementBean.cs
@@ -1,5 +1,4 @@
-#nullable enable
-using System;
+using System;
using System.ComponentModel.DataAnnotations;
namespace JJMasterData.Core.DataDictionary.Models;
diff --git a/src/MasterData.Core/DataDictionary/Models/Entity.cs b/src/MasterData.Core/DataDictionary/Models/Entity.cs
index 2659e2af7..b76d7b4f4 100644
--- a/src/MasterData.Core/DataDictionary/Models/Entity.cs
+++ b/src/MasterData.Core/DataDictionary/Models/Entity.cs
@@ -1,10 +1,7 @@
-#nullable enable
-using System;
+using System;
using System.ComponentModel.DataAnnotations;
using JJConsulting.FontAwesome;
using JJConsulting.Html.Bootstrap.Models;
-using JJMasterData.Commons.Data.Entity.Models;
-using JJMasterData.Core.UI.Components;
namespace JJMasterData.Core.DataDictionary.Models;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormActionRedirect.cs b/src/MasterData.Core/DataDictionary/Models/FormActionRedirect.cs
index 700515fec..0b187b82f 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormActionRedirect.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormActionRedirect.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+#nullable disable warnings
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.Html.Bootstrap.Models;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormActionRelationField.cs b/src/MasterData.Core/DataDictionary/Models/FormActionRelationField.cs
index 2bacbacc6..30f3e69c3 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormActionRelationField.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormActionRelationField.cs
@@ -1,4 +1,5 @@
-
+#nullable disable warnings
+
using System.Text.Json.Serialization;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElement.cs b/src/MasterData.Core/DataDictionary/Models/FormElement.cs
index 7543b6a85..8f33a57d9 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElement.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElement.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
@@ -69,6 +67,10 @@ public class FormElement : Element
[JsonPropertyName("options")]
public FormElementOptions Options { get; set; }
+ [Required]
+ [JsonPropertyName("rules")]
+ public List Rules { get; set; }
+
[Required]
[JsonPropertyName("apiOptions")]
public FormElementApiOptions ApiOptions { get; set; }
@@ -78,6 +80,7 @@ public FormElement()
Fields = new FormElementFieldList(base.Fields);
Panels = [];
Options = new FormElementOptions();
+ Rules = [];
Relationships = new FormElementRelationshipList(base.Relationships);
ApiOptions = new FormElementApiOptions();
}
@@ -102,6 +105,7 @@ public FormElement(Element element)
Panels = [];
ApiOptions = new FormElementApiOptions();
Options = new FormElementOptions();
+ Rules = [];
}
[SetsRequiredMembers]
@@ -139,6 +143,7 @@ private FormElement(
List? panels,
FormElementRelationshipList relationships,
FormElementOptions? options,
+ List? rules,
FormElementApiOptions? apiOptions)
{
base.Fields = new ElementFieldList(fields.Cast().ToList());
@@ -149,6 +154,7 @@ private FormElement(
.ToList()!;
Relationships = relationships;
Options = options ?? new FormElementOptions();
+ Rules = rules ?? [];
ApiOptions = apiOptions ?? new FormElementApiOptions();
Panels = panels ?? [];
}
@@ -226,6 +232,7 @@ public FormElement DeepCopy()
copy.Fields = Fields.DeepCopy();
copy.Options = Options.DeepCopy();
+ copy.Rules = Rules.ConvertAll(v => v.DeepCopy());
copy.Panels = Panels.ConvertAll(p => p.DeepCopy());
copy.Relationships = Relationships.DeepCopy();
copy.Indexes = Indexes.ConvertAll(i => i.DeepCopy());
@@ -233,4 +240,9 @@ public FormElement DeepCopy()
return copy;
}
+
+ public FormElementRule GetRuleById(int id)
+ {
+ return Rules.First(v => v.Id == id);
+ }
}
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementApiOptions.cs b/src/MasterData.Core/DataDictionary/Models/FormElementApiOptions.cs
index 72fd22a23..18649fbe2 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementApiOptions.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementApiOptions.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementDataFile.cs b/src/MasterData.Core/DataDictionary/Models/FormElementDataFile.cs
index 04f983fef..bd198e486 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementDataFile.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementDataFile.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
@@ -63,12 +61,8 @@ public class FormElementDataFile
[Display(Name = "Allow pasting files")]
public bool AllowPasting { get; set; } = true;
- [JsonPropertyName("showAsUploadView")]
- [Display(Name = "Show Upload Outside Modal")]
- public bool ShowAsUploadView { get; set; }
-
public FormElementDataFile DeepCopy()
{
return (FormElementDataFile)MemberwiseClone();
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementDataItem.cs b/src/MasterData.Core/DataDictionary/Models/FormElementDataItem.cs
index a9626a7a0..12eace427 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementDataItem.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementDataItem.cs
@@ -1,6 +1,6 @@
-#nullable enable
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using JJMasterData.Commons.Data;
@@ -76,10 +76,13 @@ public class FormElementDataItem
public bool SupportsFloatingLabels() => !EnableMultiSelect && !ShowIcon;
+ [MemberNotNullWhen(true, nameof(Command))]
public bool HasSqlCommand() => !string.IsNullOrWhiteSpace(Command?.Sql);
+ [MemberNotNullWhen(true, nameof(ElementMap))]
public bool HasElementMap() => ElementMap != null;
+ [MemberNotNullWhen(true, nameof(Items))]
public bool HasItems() => Items?.Count > 0;
public FormElementDataItem DeepCopy()
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementField.cs b/src/MasterData.Core/DataDictionary/Models/FormElementField.cs
index 94d11efdf..1c2bb109f 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementField.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementField.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
@@ -122,17 +120,6 @@ public class FormElementField : ElementField
[Display(Name = "Enable Exportation")]
public bool Export { get; set; }
- ///
- /// Validates possibly dangerous values in the request for .NET Framework
- ///
- ///
- /// Important for lower versions of .NET Framework to enable the parameter:
- /// httpRuntime requestValidationMode="4.5" ...
- ///
- [JsonPropertyName("validateRequest")]
- [Display(Name = "Validate Request")]
- public bool ValidateRequest { get; set; }
-
///
/// Ao alterar o conteúdo recarrega todos os campos do formulário
/// (Default=false)
@@ -201,7 +188,6 @@ public FormElementField()
{
Component = FormComponent.Text;
Export = true;
- ValidateRequest = true;
VisibleExpression = "val:1";
EnableExpression = "val:1";
TextCase = TextCase.None;
@@ -254,9 +240,8 @@ public FormElementField(ElementField elementField)
}
Export = true;
- ValidateRequest = true;
TextCase = TextCase.None;
- Actions = new();
+ Actions = [];
}
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementFieldList.cs b/src/MasterData.Core/DataDictionary/Models/FormElementFieldList.cs
index 5cad7644a..826395b4c 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementFieldList.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementFieldList.cs
@@ -1,5 +1,4 @@
-#nullable enable
-using System;
+using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementFieldSelector.cs b/src/MasterData.Core/DataDictionary/Models/FormElementFieldSelector.cs
index fd19626c1..b18a24215 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementFieldSelector.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementFieldSelector.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-namespace JJMasterData.Core.DataDictionary.Models;
+namespace JJMasterData.Core.DataDictionary.Models;
public class FormElementFieldSelector(FormElement formElement, string fieldName)
{
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementInfo.cs b/src/MasterData.Core/DataDictionary/Models/FormElementInfo.cs
index d809b28d8..f137737e5 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementInfo.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementInfo.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementOptions.cs b/src/MasterData.Core/DataDictionary/Models/FormElementOptions.cs
index 9c87ae2f2..9dcf2a9b1 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementOptions.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementOptions.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJMasterData.Core.DataDictionary.Models.Actions;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementPanel.cs b/src/MasterData.Core/DataDictionary/Models/FormElementPanel.cs
index b0869c6d3..7d845b77d 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementPanel.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementPanel.cs
@@ -1,10 +1,7 @@
-#nullable enable
-
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.FontAwesome;
using JJConsulting.Html.Bootstrap.Models;
-using JJMasterData.Commons.Data.Entity.Models;
namespace JJMasterData.Core.DataDictionary.Models;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementRelationship.cs b/src/MasterData.Core/DataDictionary/Models/FormElementRelationship.cs
index 865478bde..14fd376aa 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementRelationship.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementRelationship.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using JJConsulting.Html.Bootstrap.Models;
using JJMasterData.Commons.Data.Entity.Models;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementRelationshipList.cs b/src/MasterData.Core/DataDictionary/Models/FormElementRelationshipList.cs
index 36e8e882e..7f6865e95 100644
--- a/src/MasterData.Core/DataDictionary/Models/FormElementRelationshipList.cs
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementRelationshipList.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable disable warnings
+using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/MasterData.Core/DataDictionary/Models/FormElementRule.cs b/src/MasterData.Core/DataDictionary/Models/FormElementRule.cs
new file mode 100644
index 000000000..6278f799a
--- /dev/null
+++ b/src/MasterData.Core/DataDictionary/Models/FormElementRule.cs
@@ -0,0 +1,56 @@
+using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
+
+namespace JJMasterData.Core.DataDictionary.Models;
+
+public class FormElementRule
+{
+ [JsonPropertyName("id")]
+ public int Id { get; set; }
+
+ [Required]
+ [Display(Name = "Name")]
+ [JsonPropertyName("name")]
+ public string Name { get; set; } = string.Empty;
+
+ [Display(Name = "Run On Before Insert")]
+ [JsonPropertyName("runOnBeforeInsert")]
+ public bool RunOnBeforeInsert { get; set; } = true;
+
+ [Display(Name = "Run On Before Update")]
+ [JsonPropertyName("runOnBeforeUpdate")]
+ public bool RunOnBeforeUpdate { get; set; } = true;
+
+ [Display(Name = "Run On Before Import")]
+ [JsonPropertyName("runOnBeforeImport")]
+ public bool RunOnBeforeImport { get; set; } = true;
+
+ [Display(Name = "Run On Before Delete")]
+ [JsonPropertyName("runOnBeforeDelete")]
+ public bool RunOnBeforeDelete { get; set; }
+
+ [Display(Name = "Rule Type")]
+ [JsonPropertyName("language")]
+ public RuleLanguage Language { get; set; } = RuleLanguage.Sql;
+
+ [Display(Name = "Script")]
+ [JsonPropertyName("script")]
+ public string Script { get; set; } = string.Empty;
+
+ public bool ShouldRun(PageState pageState)
+ {
+ return pageState switch
+ {
+ PageState.Insert => RunOnBeforeInsert,
+ PageState.Update => RunOnBeforeUpdate,
+ PageState.Import => RunOnBeforeImport,
+ PageState.Delete => RunOnBeforeDelete,
+ _ => false
+ };
+ }
+
+ public FormElementRule DeepCopy()
+ {
+ return (FormElementRule)MemberwiseClone();
+ }
+}
diff --git a/src/MasterData.Core/DataDictionary/Models/GridUI.cs b/src/MasterData.Core/DataDictionary/Models/GridUI.cs
index 86c5af6f3..acd9776f0 100644
--- a/src/MasterData.Core/DataDictionary/Models/GridUI.cs
+++ b/src/MasterData.Core/DataDictionary/Models/GridUI.cs
@@ -94,12 +94,12 @@ public class GridUI
public bool EnableMultiSelect { get; set; }
///
- /// Maintains filters, order and grid pagination in the session,
+ /// Maintains filters, order and grid pagination in cookies,
/// and recovers on the first page load. (Default = false)
///
///
/// When using this property, we recommend changing the object's [Name] parameter.
- /// The [Name] property is used to compose the name of the session variable.
+ /// The [Name] property is used to compose the cookie names.
///
[JsonPropertyName("maintainValuesOnLoad")]
[Display(Name = "Save User Preferences")]
@@ -166,4 +166,4 @@ public GridUI DeepCopy()
{
return (GridUI)MemberwiseClone();
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataDictionary/Models/ProcessOptions.cs b/src/MasterData.Core/DataDictionary/Models/ProcessOptions.cs
index 89d8b187c..d258c839e 100644
--- a/src/MasterData.Core/DataDictionary/Models/ProcessOptions.cs
+++ b/src/MasterData.Core/DataDictionary/Models/ProcessOptions.cs
@@ -1,4 +1,3 @@
-
using System.Text.Json.Serialization;
namespace JJMasterData.Core.DataDictionary.Models;
@@ -9,13 +8,13 @@ public class ProcessOptions
/// SQL command to be executed before starting the import process
///
[JsonPropertyName("commandBeforeProcess")]
- public string CommandBeforeProcess { get; set; }
+ public string? CommandBeforeProcess { get; set; }
///
/// SQL command to be executed at the end of the import process
///
[JsonPropertyName("commandAfterProcess")]
- public string CommandAfterProcess { get; set; }
+ public string? CommandAfterProcess { get; set; }
[JsonPropertyName("scope")]
public ProcessScope Scope { get; set; } = ProcessScope.User;
diff --git a/src/MasterData.Core/DataDictionary/Models/RuleLanguage.cs b/src/MasterData.Core/DataDictionary/Models/RuleLanguage.cs
new file mode 100644
index 000000000..4098b7065
--- /dev/null
+++ b/src/MasterData.Core/DataDictionary/Models/RuleLanguage.cs
@@ -0,0 +1,11 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace JJMasterData.Core.DataDictionary.Models;
+
+public enum RuleLanguage
+{
+ [Display(Name = "SQL")]
+ Sql = 0,
+ [Display(Name = "JavaScript")]
+ JavaScript = 1
+}
diff --git a/src/MasterData.Core/DataDictionary/Repository/Abstractions/IDataDictionaryRepository.cs b/src/MasterData.Core/DataDictionary/Repository/Abstractions/IDataDictionaryRepository.cs
index 33f17e99e..6205af6ba 100644
--- a/src/MasterData.Core/DataDictionary/Repository/Abstractions/IDataDictionaryRepository.cs
+++ b/src/MasterData.Core/DataDictionary/Repository/Abstractions/IDataDictionaryRepository.cs
@@ -18,7 +18,7 @@ public interface IDataDictionaryRepository
ValueTask> GetElementNameListAsync();
List GetFormElementList(bool? apiSync = null);
- Task> GetFormElementInfoListAsync(DataDictionaryFilter filters, OrderByData orderByData, int recordsPerPage, int currentPage);
+ Task> GetFormElementInfoListAsync(DataDictionaryFilter filters, OrderByData? orderByData, int recordsPerPage, int currentPage);
Task ExistsAsync(string elementName);
Task InsertOrReplaceAsync(FormElement formElement);
Task InsertOrReplaceAsync(IEnumerable formElements);
diff --git a/src/MasterData.Core/DataDictionary/Repository/FileSystemDataDictionaryOptions.cs b/src/MasterData.Core/DataDictionary/Repository/FileSystemDataDictionaryOptions.cs
index ab35e8c86..e878f5976 100644
--- a/src/MasterData.Core/DataDictionary/Repository/FileSystemDataDictionaryOptions.cs
+++ b/src/MasterData.Core/DataDictionary/Repository/FileSystemDataDictionaryOptions.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
namespace JJMasterData.Core.DataDictionary.Repository;
public class FileSystemDataDictionaryOptions
diff --git a/src/MasterData.Core/DataDictionary/Repository/FileSystemDataDictionaryRepository.cs b/src/MasterData.Core/DataDictionary/Repository/FileSystemDataDictionaryRepository.cs
index b9c42940e..3af273af2 100644
--- a/src/MasterData.Core/DataDictionary/Repository/FileSystemDataDictionaryRepository.cs
+++ b/src/MasterData.Core/DataDictionary/Repository/FileSystemDataDictionaryRepository.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable disable warnings
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
diff --git a/src/MasterData.Core/DataDictionary/Repository/SqlDataDictionaryRepository.cs b/src/MasterData.Core/DataDictionary/Repository/SqlDataDictionaryRepository.cs
index edb2f2f02..2fcb4ec2e 100644
--- a/src/MasterData.Core/DataDictionary/Repository/SqlDataDictionaryRepository.cs
+++ b/src/MasterData.Core/DataDictionary/Repository/SqlDataDictionaryRepository.cs
@@ -1,4 +1,5 @@
-#nullable enable
+
+#nullable disable warnings
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/MasterData.Core/DataDictionary/Services/ActionsService.cs b/src/MasterData.Core/DataDictionary/Services/ActionsService.cs
index 205d80c4c..a85ca250f 100644
--- a/src/MasterData.Core/DataDictionary/Services/ActionsService.cs
+++ b/src/MasterData.Core/DataDictionary/Services/ActionsService.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable disable warnings
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -7,7 +8,6 @@
using JJMasterData.Core.DataDictionary.Models.Actions;
using JJMasterData.Core.DataDictionary.Repository.Abstractions;
using JJMasterData.Core.DataManager.Expressions.Abstractions;
-using JJMasterData.Core.Extensions;
using Microsoft.Extensions.Localization;
namespace JJMasterData.Core.DataDictionary.Services;
@@ -19,7 +19,7 @@ public class ActionsService(IValidationDictionary validationDictionary,
IEnumerable pluginHandlers)
: DataDictionaryServiceBase(validationDictionary, dataDictionaryRepository,stringLocalizer)
{
- public async Task DeleteActionAsync(string elementName, string actionName, ActionSource context, string fieldName = null)
+ public async Task DeleteActionAsync(string elementName, string actionName, ActionSource context, string? fieldName = null)
{
var dicParser = await DataDictionaryRepository.GetFormElementAsync(elementName);
DeleteAction(dicParser, actionName, context, fieldName);
@@ -28,7 +28,7 @@ public async Task DeleteActionAsync(string elementName, string actionName,
return true;
}
- private static void DeleteAction(FormElement formElement, string originalName, ActionSource context, string fieldName = null)
+ private static void DeleteAction(FormElement formElement, string originalName, ActionSource context, string? fieldName = null)
{
if (originalName == null)
return;
@@ -63,7 +63,7 @@ private static void DeleteAction(FormElement formElement, string originalName, A
}
}
- public async Task SaveAction(string elementName, BasicAction action, ActionSource context, string originalName, string fieldName = null)
+ public async Task SaveAction(string elementName, BasicAction action, ActionSource context, string? originalName, string? fieldName = null)
{
var formElement = await DataDictionaryRepository.GetFormElementAsync(elementName);
ValidateActionName(formElement, action.Name, originalName, context, fieldName);
@@ -111,7 +111,7 @@ public async Task SaveAction(string elementName, BasicAction action, Actio
return true;
}
- private void ValidateActionName(FormElement formElement, string actionName, string originalName, ActionSource context, string fieldName = null)
+ private void ValidateActionName(FormElement formElement, string actionName, string originalName, ActionSource context, string? fieldName = null)
{
if (string.IsNullOrWhiteSpace(actionName))
{
@@ -149,7 +149,7 @@ private void ValidateActionName(FormElement formElement, string actionName, stri
}
}
- private void ValidateAction(FormElement formElement, BasicAction action, [CanBeNull] string fieldName = null)
+ private void ValidateAction(FormElement formElement, BasicAction action, [CanBeNull] string? fieldName = null)
{
if (string.IsNullOrWhiteSpace(action.VisibleExpression))
AddError(nameof(action.VisibleExpression), StringLocalizer["Required [VisibleExpression] field"]);
@@ -219,7 +219,7 @@ private void ValidateAction(FormElement formElement, BasicAction action, [CanBeN
}
}
- public async Task SortActionsAsync(string elementName, string[] listAction, ActionSource actionContext, string fieldName)
+ public async Task SortActionsAsync(string elementName, string[] listAction, ActionSource actionContext, string? fieldName)
{
var formElement = await DataDictionaryRepository.GetFormElementAsync(elementName);
for (int i = 0; i < listAction.Length; i++)
diff --git a/src/MasterData.Core/DataDictionary/Services/DataDictionaryLocalizationService.cs b/src/MasterData.Core/DataDictionary/Services/DataDictionaryLocalizationService.cs
index fb194985d..5a09c1c6e 100644
--- a/src/MasterData.Core/DataDictionary/Services/DataDictionaryLocalizationService.cs
+++ b/src/MasterData.Core/DataDictionary/Services/DataDictionaryLocalizationService.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections;
using System.Collections.Generic;
@@ -86,7 +84,7 @@ private async Task AddDataItemAsync(HashSet keys, FormElementDataItem? d
if (dataItem.HasItems())
{
- foreach (var item in dataItem.Items!)
+ foreach (var item in dataItem.Items)
{
AddKey(keys, item.Description);
}
diff --git a/src/MasterData.Core/DataDictionary/Services/DataDictionaryServiceBase.cs b/src/MasterData.Core/DataDictionary/Services/DataDictionaryServiceBase.cs
index 6412cc99c..bd0109f1b 100644
--- a/src/MasterData.Core/DataDictionary/Services/DataDictionaryServiceBase.cs
+++ b/src/MasterData.Core/DataDictionary/Services/DataDictionaryServiceBase.cs
@@ -6,7 +6,6 @@
using JJMasterData.Commons.Validations;
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataDictionary.Repository.Abstractions;
-using JJMasterData.Core.UI.Components;
using Microsoft.Extensions.Localization;
namespace JJMasterData.Core.DataDictionary.Services;
@@ -91,6 +90,17 @@ public bool ValidateName(string name)
return validationDictionary.IsValid;
}
+ protected bool ValidateScriptName(string name, string fieldName = "Name")
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ AddError(fieldName, StringLocalizer["Required [Name] field"]);
+ return false;
+ }
+
+ return true;
+ }
+
protected static bool ValidateExpression(string value, IEnumerable args)
{
return args.Any(value.StartsWith);
@@ -120,4 +130,4 @@ public async ValueTask> GetElementsDictionaryAsync()
return elementList;
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataDictionary/Services/ElementExportService.cs b/src/MasterData.Core/DataDictionary/Services/ElementExportService.cs
index 104586957..bade5bc61 100644
--- a/src/MasterData.Core/DataDictionary/Services/ElementExportService.cs
+++ b/src/MasterData.Core/DataDictionary/Services/ElementExportService.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
diff --git a/src/MasterData.Core/DataDictionary/Services/ElementImportService.cs b/src/MasterData.Core/DataDictionary/Services/ElementImportService.cs
index 6d1942a29..2426c3b1a 100644
--- a/src/MasterData.Core/DataDictionary/Services/ElementImportService.cs
+++ b/src/MasterData.Core/DataDictionary/Services/ElementImportService.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
@@ -10,7 +11,7 @@ namespace JJMasterData.Core.DataDictionary.Services;
public class ElementImportService(IDataDictionaryRepository dataDictionaryRepository)
{
- public async Task Import(MemoryStream file)
+ public async Task Import(Stream file)
{
file.Seek(0, SeekOrigin.Begin);
@@ -20,9 +21,8 @@ public async Task Import(MemoryStream file)
return true;
}
-
-#if NET
- public async Task ImportZipFile(MemoryStream ms)
+
+ public async Task ImportZipFile(Stream ms)
{
using var zip = new ZipArchive(ms, ZipArchiveMode.Read, leaveOpen: true);
@@ -45,5 +45,4 @@ private static IEnumerable GetFormElements(ZipArchive zip)
yield return formElement;
}
}
-#endif
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataDictionary/Services/ElementService.cs b/src/MasterData.Core/DataDictionary/Services/ElementService.cs
index 3d3e63e37..44d6f87df 100644
--- a/src/MasterData.Core/DataDictionary/Services/ElementService.cs
+++ b/src/MasterData.Core/DataDictionary/Services/ElementService.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System;
+using System;
using System.Globalization;
using System.Threading.Tasks;
using JJConsulting.Html;
@@ -13,9 +11,6 @@
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataDictionary.Repository.Abstractions;
using JJMasterData.Core.DataDictionary.Structure;
-using JJMasterData.Core.Html;
-using JJMasterData.Core.Http.Abstractions;
-using JJMasterData.Core.Tasks;
using JJMasterData.Core.UI.Components;
using Microsoft.Extensions.Localization;
@@ -164,7 +159,7 @@ await DataDictionaryRepository.GetFormElementInfoListAsync(filter, args.OrderBy,
args.TotalOfRecords = result.TotalOfRecords;
};
- formView.GridView.OnRenderCellAsync += (_, args) =>
+ formView.GridView.OnRenderCell += (_, args) =>
{
if (args.Field.Name == DataDictionaryStructure.Name)
{
@@ -195,10 +190,9 @@ await DataDictionaryRepository.GetFormElementInfoListAsync(filter, args.OrderBy,
.AppendText(relativeDateFormatter.ToRelativeString(lastModified));
}
- return ValueTaskHelper.CompletedTask;
};
- formView.GridView.OnRenderActionAsync += (_, args) =>
+ formView.GridView.OnRenderAction += (_, args) =>
{
var elementName = args.FieldValues["name"]?.ToString();
@@ -220,7 +214,6 @@ await DataDictionaryRepository.GetFormElementInfoListAsync(filter, args.OrderBy,
break;
}
- return ValueTaskHelper.CompletedTask;
};
return formView;
@@ -229,8 +222,8 @@ await DataDictionaryRepository.GetFormElementInfoListAsync(filter, args.OrderBy,
#endregion
- public Task DeleteAsync(string? elementName)
+ public Task DeleteAsync(string elementName)
{
return DataDictionaryRepository.DeleteAsync(elementName);
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataDictionary/Services/FieldService.cs b/src/MasterData.Core/DataDictionary/Services/FieldService.cs
index 99506d0b6..9498151c8 100644
--- a/src/MasterData.Core/DataDictionary/Services/FieldService.cs
+++ b/src/MasterData.Core/DataDictionary/Services/FieldService.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+#nullable disable warnings
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JJMasterData.Commons.Data.Entity.Models;
@@ -6,8 +7,6 @@
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataDictionary.Repository.Abstractions;
using JJMasterData.Core.DataManager.Expressions.Abstractions;
-using JJMasterData.Core.Extensions;
-using JJMasterData.Core.Tasks;
using Microsoft.Extensions.Localization;
namespace JJMasterData.Core.DataDictionary.Services;
@@ -20,7 +19,7 @@ public class FieldService(
IStringLocalizer stringLocalizer)
: DataDictionaryServiceBase(validationDictionary, dataDictionaryRepository,stringLocalizer)
{
- public async Task SaveFieldAsync(string elementName, FormElementField field, string originalName)
+ public async Task SaveFieldAsync(string elementName, FormElementField field, string? originalName)
{
var formElement = await DataDictionaryRepository.GetFormElementAsync(elementName);
@@ -93,7 +92,7 @@ private static void RemoveUnusedProperties(FormElementField field)
}
}
- private async ValueTask ValidateFieldAsync(FormElement formElement, FormElementField field, string originalName)
+ private async ValueTask ValidateFieldAsync(FormElement formElement, FormElementField field, string? originalName)
{
ValidateName(field.Name);
@@ -276,7 +275,7 @@ private ValueTask ValidateDataItemAsync(FormElementField field)
if (dataItem == null)
{
AddError("DataItem", StringLocalizer["DataItem cannot be empty."]);
- return ValueTaskHelper.CompletedTask;
+ return ValueTask.CompletedTask;
}
if (dataItem.DataItemType == DataItemType.SqlCommand)
@@ -284,7 +283,7 @@ private ValueTask ValidateDataItemAsync(FormElementField field)
if (dataItem.Command == null)
{
AddError("Command", StringLocalizer["[Command] required"]);
- return ValueTaskHelper.CompletedTask;
+ return ValueTask.CompletedTask;
}
if (string.IsNullOrEmpty(dataItem.Command.Sql))
@@ -307,7 +306,7 @@ private ValueTask ValidateDataItemAsync(FormElementField field)
return ValidateDataElementMapAsync(field);
}
- return ValueTaskHelper.CompletedTask;
+ return ValueTask.CompletedTask;
}
private void ValidateManualItems(List items)
diff --git a/src/MasterData.Core/DataDictionary/Services/FormElementRulesService.cs b/src/MasterData.Core/DataDictionary/Services/FormElementRulesService.cs
new file mode 100644
index 000000000..f8352f48d
--- /dev/null
+++ b/src/MasterData.Core/DataDictionary/Services/FormElementRulesService.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using JJMasterData.Core.DataDictionary.Models;
+using JJMasterData.Core.DataDictionary.Repository.Abstractions;
+using Microsoft.Extensions.Localization;
+
+namespace JJMasterData.Core.DataDictionary.Services;
+
+public class FormElementRulesService(
+ IValidationDictionary validationDictionary,
+ IDataDictionaryRepository dataDictionaryRepository,
+ IStringLocalizer stringLocalizer)
+ : DataDictionaryServiceBase(validationDictionary, dataDictionaryRepository, stringLocalizer)
+{
+ public async Task SaveAsync(string elementName, FormElementRule rule)
+ {
+ var formElement = await DataDictionaryRepository.GetFormElementAsync(elementName);
+
+ if (!Validate(rule, formElement))
+ return;
+
+ if (rule.Id == 0)
+ {
+ rule.Id = formElement.Rules.Count == 0
+ ? 1
+ : formElement.Rules.Max(v => v.Id) + 1;
+
+ formElement.Rules.Add(rule);
+ }
+ else
+ {
+ for (var i = 0; i < formElement.Rules.Count; i++)
+ {
+ if (formElement.Rules[i].Id != rule.Id)
+ continue;
+
+ formElement.Rules[i] = rule;
+ break;
+ }
+ }
+
+ await DataDictionaryRepository.InsertOrReplaceAsync(formElement);
+ }
+
+ public async Task DeleteAsync(string elementName, int ruleId)
+ {
+ var formElement = await DataDictionaryRepository.GetFormElementAsync(elementName);
+ var rule = formElement.Rules.FirstOrDefault(v => v.Id == ruleId);
+ if (rule == null)
+ return;
+
+ formElement.Rules.Remove(rule);
+ await DataDictionaryRepository.InsertOrReplaceAsync(formElement);
+ }
+
+ public bool Validate(FormElementRule rule, FormElement formElement)
+ {
+ ValidateScriptName(rule.Name);
+
+ if (!rule.RunOnBeforeInsert && !rule.RunOnBeforeUpdate && !rule.RunOnBeforeDelete && !rule.RunOnBeforeImport)
+ AddError(nameof(rule.RunOnBeforeInsert), StringLocalizer["Select at least one operation."]);
+
+ if (string.IsNullOrWhiteSpace(rule.Script))
+ AddError(nameof(rule.Script), StringLocalizer["Required [Script] field"]);
+
+ if (formElement.Rules.Any(v =>
+ v.Id != rule.Id &&
+ v.Name.Equals(rule.Name, StringComparison.OrdinalIgnoreCase)))
+ {
+ AddError(nameof(rule.Name), StringLocalizer["There is already a rule with this name."]);
+ }
+
+ return IsValid;
+ }
+}
diff --git a/src/MasterData.Core/DataDictionary/Services/PanelService.cs b/src/MasterData.Core/DataDictionary/Services/PanelService.cs
index a21bb5d3d..feb781006 100644
--- a/src/MasterData.Core/DataDictionary/Services/PanelService.cs
+++ b/src/MasterData.Core/DataDictionary/Services/PanelService.cs
@@ -1,11 +1,9 @@
-#nullable enable
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataDictionary.Repository.Abstractions;
using JJMasterData.Core.DataManager.Expressions.Abstractions;
-using JJMasterData.Core.Extensions;
using Microsoft.Extensions.Localization;
namespace JJMasterData.Core.DataDictionary.Services;
diff --git a/src/MasterData.Core/DataDictionary/Services/RelationshipsService.cs b/src/MasterData.Core/DataDictionary/Services/RelationshipsService.cs
index 33cdb0aa0..73d53e268 100644
--- a/src/MasterData.Core/DataDictionary/Services/RelationshipsService.cs
+++ b/src/MasterData.Core/DataDictionary/Services/RelationshipsService.cs
@@ -1,5 +1,4 @@
-#nullable enable
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JJMasterData.Commons.Data.Entity.Models;
diff --git a/src/MasterData.Core/DataDictionary/Services/ScriptsService.cs b/src/MasterData.Core/DataDictionary/Services/ScriptsService.cs
index fa0c0642c..e7bd4f90b 100644
--- a/src/MasterData.Core/DataDictionary/Services/ScriptsService.cs
+++ b/src/MasterData.Core/DataDictionary/Services/ScriptsService.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
diff --git a/src/MasterData.Core/DataDictionary/Structure/DataDictionaryFilter.cs b/src/MasterData.Core/DataDictionary/Structure/DataDictionaryFilter.cs
index 4efda7e15..67205e015 100644
--- a/src/MasterData.Core/DataDictionary/Structure/DataDictionaryFilter.cs
+++ b/src/MasterData.Core/DataDictionary/Structure/DataDictionaryFilter.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Collections.Generic;
diff --git a/src/MasterData.Core/DataDictionary/Structure/DataDictionaryFormElementFactory.cs b/src/MasterData.Core/DataDictionary/Structure/DataDictionaryFormElementFactory.cs
index bc39c02d3..6f839acfc 100644
--- a/src/MasterData.Core/DataDictionary/Structure/DataDictionaryFormElementFactory.cs
+++ b/src/MasterData.Core/DataDictionary/Structure/DataDictionaryFormElementFactory.cs
@@ -1,10 +1,10 @@
+#nullable disable warnings
using System.Collections.Generic;
using JJConsulting.FontAwesome;
using JJMasterData.Commons.Data.Entity.Models;
using JJMasterData.Core.Configuration.Options;
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataDictionary.Models.Actions;
-using JJMasterData.Core.Http.Abstractions;
using JJMasterData.Core.UI;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
diff --git a/src/MasterData.Core/DataDictionary/Structure/DataDictionaryModel.cs b/src/MasterData.Core/DataDictionary/Structure/DataDictionaryModel.cs
index c5715bc25..d9c825044 100644
--- a/src/MasterData.Core/DataDictionary/Structure/DataDictionaryModel.cs
+++ b/src/MasterData.Core/DataDictionary/Structure/DataDictionaryModel.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System;
using System.Collections.Generic;
diff --git a/src/MasterData.Core/DataManager/DataHelper.cs b/src/MasterData.Core/DataManager/DataHelper.cs
index 487598f65..62cd96bcc 100644
--- a/src/MasterData.Core/DataManager/DataHelper.cs
+++ b/src/MasterData.Core/DataManager/DataHelper.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -257,4 +255,4 @@ public static void RemoveNullValues(Dictionary? values)
values.Remove(key);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataManager/Exportation/Abstractions/DataExportationWriterBase.cs b/src/MasterData.Core/DataManager/Exportation/Abstractions/DataExportationWriterBase.cs
index 0e18cd870..051f20d47 100644
--- a/src/MasterData.Core/DataManager/Exportation/Abstractions/DataExportationWriterBase.cs
+++ b/src/MasterData.Core/DataManager/Exportation/Abstractions/DataExportationWriterBase.cs
@@ -1,3 +1,4 @@
+#nullable disable warnings
using System;
using System.Collections.Generic;
using System.IO;
@@ -5,9 +6,10 @@
using System.Threading;
using System.Threading.Tasks;
using System.Web;
+using JJConsulting.MasterData.Storage.Abstractions;
using JJMasterData.Commons.Data.Entity.Repository;
using JJMasterData.Commons.Exceptions;
-using JJMasterData.Commons.Security.Cryptography.Abstractions;
+using JJMasterData.Commons.Storage;
using JJMasterData.Commons.Tasks;
using JJMasterData.Commons.Tasks.Progress;
using JJMasterData.Commons.Util;
@@ -15,7 +17,6 @@
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataManager.Exportation.Configuration;
using JJMasterData.Core.DataManager.Expressions;
-using JJMasterData.Core.DataManager.IO;
using JJMasterData.Core.DataManager.Models;
using JJMasterData.Core.UI.Components;
using Microsoft.Extensions.Localization;
@@ -25,7 +26,6 @@
namespace JJMasterData.Core.DataManager.Exportation.Abstractions;
public abstract class DataExportationWriterBase(
- IEncryptionService encryptionService,
ExpressionsService expressionsService,
IStringLocalizer stringLocalizer,
IOptionsSnapshot options,
@@ -35,27 +35,22 @@ public abstract class DataExportationWriterBase(
public event EventHandler OnProgressChanged;
protected const int RecordsPerPage = 100000;
-
+
+ private List _fields;
+
#region "Properties"
private DataExportationReporter _processReporter;
- private List _fields;
- private FormFilePathBuilder _pathBuilder;
- private IEncryptionService EncryptionService { get; } = encryptionService;
private ExpressionsService ExpressionsService { get; } = expressionsService;
protected IStringLocalizer StringLocalizer { get; } = stringLocalizer;
private IOptionsSnapshot Options { get; } = options;
private ILogger Logger { get; } = logger;
- private FormFilePathBuilder PathBuilder => _pathBuilder ??= new FormFilePathBuilder(FormElement);
-
- public string AbsoluteUri { get; internal set; }
- private string GetFolderPath(FormElementField field, Dictionary values)
- {
- return PathBuilder.GetFolderPath(field, values);
- }
+ internal FileDownloaderFactory FileDownloaderFactory { get; set; }
+ internal IFileStorage FileStorage { get; set; }
+ internal string AbsoluteUri { get; set; }
protected List VisibleFields
{
@@ -138,41 +133,16 @@ public string FolderPath
get
{
var path = Options.Value.ExportationFolderPath;
- string folderPath = DataExportationHelper.GetFolderPath(FormElement, path, UserId);
-
- CreateFolderPathIfNotExits(folderPath);
-
- return folderPath;
- }
- }
-
- private static void CreateFolderPathIfNotExits(string folderPath)
- {
- try
- {
- if (folderPath != null && !Directory.Exists(folderPath))
- Directory.CreateDirectory(folderPath);
- }
- catch (Exception ex)
- {
- const string message = "Error on create directory, set a valid ExportationFolderPath on JJMasterData Options.";
- throw new JJMasterDataException(message, ex);
+ return DataExportationHelper.GetExportationFolderPath(FormElement, path, UserId);
}
}
public string UserId { get; set; }
-#if NETFRAMEWORK
- internal HttpContext HttpContext { get; set; }
-#endif
-
#endregion
public async Task RunWorkerAsync(CancellationToken token)
{
-#if NETFRAMEWORK
- HttpContext.Current = HttpContext;
-#endif
if (FormElement == null)
throw new ArgumentNullException(nameof(FormElement));
@@ -185,14 +155,28 @@ public async Task RunWorkerAsync(CancellationToken token)
Reporter(ProcessReporter);
- var filePath = Path.Combine(FolderPath, GetFilePath());
+ var fileName = GetFileName();
+ var tempFilePath = Path.GetTempFileName();
- using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite))
+ try
{
- await GenerateDocument(fs, token);
+ await using (var fs = new FileStream(tempFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 81920, true))
+ {
+ await GenerateDocument(fs, token);
+ }
+
+ await using var readStream = new FileStream(tempFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 81920, true);
+ var fullPath = FileStoragePath.Combine(FolderPath, fileName);
+ await FileStorage.SaveAsync(fullPath, readStream, true, token);
+ }
+ finally
+ {
+ if (File.Exists(tempFilePath))
+ File.Delete(tempFilePath);
}
- ProcessReporter.FilePath = filePath;
+ ProcessReporter.FolderPath = FolderPath;
+ ProcessReporter.FileName = fileName;
ProcessReporter.EndDate = DateTime.Now;
ProcessReporter.HasError = false;
@@ -208,14 +192,6 @@ public async Task RunWorkerAsync(CancellationToken token)
case ThreadAbortException:
ProcessReporter.Message = StringLocalizer["Process aborted by the user."];
break;
- case IOException:
- if (FileIO.IsFileLocked(FolderPath))
- ProcessReporter.Message =
- StringLocalizer[
- "File is already being used by another process. Try downloading it from \"Recently generated files\"."];
- else
- goto default;
- break;
case JJMasterDataException:
ProcessReporter.Message = ex.Message;
break;
@@ -226,8 +202,6 @@ public async Task RunWorkerAsync(CancellationToken token)
break;
}
- if (File.Exists(FolderPath) && !FileIO.IsFileLocked(FolderPath))
- File.Delete(FolderPath);
}
finally
{
@@ -243,7 +217,8 @@ protected void Reporter(DataExportationReporter processReporter)
public abstract Task GenerateDocument(Stream ms, CancellationToken token);
- protected string GetFileLink(FormElementField field, Dictionary row, string value)
+ protected string GetFileLink(FormElement formElement, FormElementField field, Dictionary row,
+ string value)
{
if (!field.DataFile!.ExportAsLink)
return null;
@@ -255,11 +230,16 @@ protected string GetFileLink(FormElementField field, Dictionary
if (files.Length != 1)
return null;
- var filePath = GetFolderPath(field, row) + value;
- return JJFileDownloader.GetExternalDownloadLink(EncryptionService, AbsoluteUri, filePath);
+ var fileName = Path.GetFileName(files[0]);
+ if (string.IsNullOrEmpty(fileName))
+ return null;
+
+ var downloader = FileDownloaderFactory.Create(formElement, field, row, fileName);
+
+ return new Uri(new Uri(AbsoluteUri), downloader.GetDownloadUrl(AbsoluteUri)).AbsoluteUri;
}
- private string GetFilePath()
+ private string GetFileName()
{
string fileName;
var exportActionFileName = FormElement.Options.GridToolbarActions.ExportAction.FileName;
@@ -295,4 +275,10 @@ private string GetFilePath()
return $"{fileName}_{DateTime.Now:yyyMMdd_HHmmss}.{extension}";
}
-}
\ No newline at end of file
+
+ public async Task OpenReadAsync()
+ {
+ var fullPath = FileStoragePath.Combine(ProcessReporter.FolderPath, ProcessReporter.FileName);
+ return await FileStorage.OpenReadAsync(fullPath);
+ }
+}
diff --git a/src/MasterData.Core/DataManager/Exportation/Abstractions/IExcelWriter.cs b/src/MasterData.Core/DataManager/Exportation/Abstractions/IExcelWriter.cs
index 14d021de3..4f021435a 100644
--- a/src/MasterData.Core/DataManager/Exportation/Abstractions/IExcelWriter.cs
+++ b/src/MasterData.Core/DataManager/Exportation/Abstractions/IExcelWriter.cs
@@ -1,4 +1,4 @@
-using JJMasterData.Commons.Tasks;
+using System;
using JJMasterData.Core.UI.Events.Args;
namespace JJMasterData.Core.DataManager.Exportation.Abstractions;
@@ -8,5 +8,5 @@ public interface IExcelWriter : IExportationWriter
bool ShowBorder { get; set; }
bool ShowRowStriped { get; set; }
- event AsyncEventHandler OnRenderCellAsync;
+ event EventHandler OnRenderCell;
}
diff --git a/src/MasterData.Core/DataManager/Exportation/Abstractions/IPdfWriter.cs b/src/MasterData.Core/DataManager/Exportation/Abstractions/IPdfWriter.cs
index 76430e954..692a54f0f 100644
--- a/src/MasterData.Core/DataManager/Exportation/Abstractions/IPdfWriter.cs
+++ b/src/MasterData.Core/DataManager/Exportation/Abstractions/IPdfWriter.cs
@@ -1,5 +1,4 @@
using System;
-using JJMasterData.Commons.Tasks;
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.UI.Events.Args;
@@ -8,7 +7,6 @@ namespace JJMasterData.Core.DataManager.Exportation.Abstractions;
public interface IPdfWriter : IExportationWriter
{
event EventHandler OnRenderCell;
- event AsyncEventHandler OnRenderCellAsync;
public FormElement FormElement { get; set; }
public bool ShowBorder { get; set; }
@@ -16,4 +14,4 @@ public interface IPdfWriter : IExportationWriter
public bool ShowRowStriped { get; set; }
public bool IsLandscape { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataManager/Exportation/Abstractions/ITextWriter.cs b/src/MasterData.Core/DataManager/Exportation/Abstractions/ITextWriter.cs
index 0ad8fd8ed..12d4709c2 100644
--- a/src/MasterData.Core/DataManager/Exportation/Abstractions/ITextWriter.cs
+++ b/src/MasterData.Core/DataManager/Exportation/Abstractions/ITextWriter.cs
@@ -1,4 +1,4 @@
-using JJMasterData.Commons.Tasks;
+using System;
using JJMasterData.Core.UI.Events.Args;
namespace JJMasterData.Core.DataManager.Exportation.Abstractions;
@@ -6,5 +6,5 @@ namespace JJMasterData.Core.DataManager.Exportation.Abstractions;
public interface ITextWriter : IExportationWriter
{
string Delimiter { get; set; }
- event AsyncEventHandler OnRenderCellAsync;
-}
\ No newline at end of file
+ event EventHandler OnRenderCell;
+}
diff --git a/src/MasterData.Core/DataManager/Exportation/Configuration/ExportOptions.cs b/src/MasterData.Core/DataManager/Exportation/Configuration/ExportOptions.cs
index 2ca3e1ab6..76bb85763 100644
--- a/src/MasterData.Core/DataManager/Exportation/Configuration/ExportOptions.cs
+++ b/src/MasterData.Core/DataManager/Exportation/Configuration/ExportOptions.cs
@@ -1,5 +1,5 @@
-using JJMasterData.Commons.Util;
-using JJMasterData.Core.Http.Abstractions;
+#nullable disable warnings
+using JJMasterData.Commons.Util;
namespace JJMasterData.Core.DataManager.Exportation.Configuration;
@@ -20,16 +20,21 @@ public class ExportOptions
public bool IsLandScape { get; set; } = false;
public string Delimiter { get; set; } = ";";
- internal static ExportOptions LoadFromForm(IFormValues formValues, string componentName)
+ internal static ExportOptions LoadFromForm(IHttpContextAccessor httpContextAccessor, string componentName)
{
var expConfig = new ExportOptions();
- if (formValues[componentName + FileName] != null)
+
+ if (!httpContextAccessor.HttpContext!.Request.HasFormContentType)
+ return expConfig;
+
+ var form = httpContextAccessor.HttpContext!.Request.Form;
+ if (form.TryGetValue(componentName + FileName, out var fileName))
{
- expConfig.FileExtension = (ExportFileExtension)int.Parse(formValues[componentName + FileName]);
- expConfig.IsLandScape = StringManager.ParseBool(formValues[componentName + TableOrientation]);
- expConfig.ExportFirstLine = StringManager.ParseBool(formValues[componentName + ExportTableFirstLine]);
- expConfig.ExportAllFields = StringManager.ParseBool(formValues[componentName + ExportAll]);
- expConfig.Delimiter = formValues[componentName + ExportDelimiter];
+ expConfig.FileExtension = (ExportFileExtension)int.Parse(fileName.ToString());
+ expConfig.IsLandScape = StringManager.ParseBool(form[componentName + TableOrientation]);
+ expConfig.ExportFirstLine = StringManager.ParseBool(form[componentName + ExportTableFirstLine]);
+ expConfig.ExportAllFields = StringManager.ParseBool(form[componentName + ExportAll]);
+ expConfig.Delimiter = form[componentName + ExportDelimiter];
}
return expConfig;
diff --git a/src/MasterData.Core/DataManager/Exportation/DataExportationHelper.cs b/src/MasterData.Core/DataManager/Exportation/DataExportationHelper.cs
index 04d40b074..efdeefe8a 100644
--- a/src/MasterData.Core/DataManager/Exportation/DataExportationHelper.cs
+++ b/src/MasterData.Core/DataManager/Exportation/DataExportationHelper.cs
@@ -1,17 +1,15 @@
-#nullable enable
-
using System.IO;
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.UI.Components;
namespace JJMasterData.Core.DataManager.Exportation;
-internal static class DataExportationHelper
+public static class DataExportationHelper
{
///
/// Path where the files are generated.
///
- public static string GetFolderPath(FormElement formElement, string path, string userId)
+ public static string GetExportationFolderPath(FormElement formElement, string path, string userId)
{
var processOptions = formElement.Options.GridToolbarActions.ExportAction.ProcessOptions;
var folderPath = Path.Combine(path, formElement.Name);
@@ -23,9 +21,9 @@ public static string GetFolderPath(FormElement formElement, string path, string
return folderPath;
}
- public static string GetFolderPath(JJDataExportation dataExportation)
+ public static string GetExportationFolderPath(JJDataExportation dataExportation)
{
var path = dataExportation.MasterDataOptions.ExportationFolderPath;
- return GetFolderPath(dataExportation.FormElement , path, dataExportation.UserId);
+ return GetExportationFolderPath(dataExportation.FormElement , path, dataExportation.UserId);
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataManager/Exportation/DataExportationProgressDto.cs b/src/MasterData.Core/DataManager/Exportation/DataExportationProgressDto.cs
index 8de89bdc6..63b2d5746 100644
--- a/src/MasterData.Core/DataManager/Exportation/DataExportationProgressDto.cs
+++ b/src/MasterData.Core/DataManager/Exportation/DataExportationProgressDto.cs
@@ -1,4 +1,5 @@
-
+#nullable disable warnings
+
using System.Text.Json.Serialization;
diff --git a/src/MasterData.Core/DataManager/Exportation/DataExportationReporter.cs b/src/MasterData.Core/DataManager/Exportation/DataExportationReporter.cs
index 4d781ecbf..0b7dcf75e 100644
--- a/src/MasterData.Core/DataManager/Exportation/DataExportationReporter.cs
+++ b/src/MasterData.Core/DataManager/Exportation/DataExportationReporter.cs
@@ -1,33 +1,33 @@
-using System;
+#nullable disable warnings
+using System;
using JJMasterData.Commons.Tasks.Progress;
namespace JJMasterData.Core.DataManager.Exportation;
public class DataExportationReporter : ProgressReporter
{
- private int _totalProcessed;
public int TotalProcessed
{
- get => _totalProcessed;
+ get;
set
{
- _totalProcessed = value;
+ field = value;
UpdatePercentage();
}
}
- private int _totalOfRecords;
public int TotalOfRecords
{
- get => _totalOfRecords;
+ get;
set
{
- _totalOfRecords = value;
+ field = value;
UpdatePercentage();
}
}
- public string FilePath { get; set; }
+ public string FolderPath { get; set; }
+ public string FileName { get; set; }
private void UpdatePercentage()
{
diff --git a/src/MasterData.Core/DataManager/Exportation/DataExportationWriterFactory.cs b/src/MasterData.Core/DataManager/Exportation/DataExportationWriterFactory.cs
index c6285cd72..ff448a60f 100644
--- a/src/MasterData.Core/DataManager/Exportation/DataExportationWriterFactory.cs
+++ b/src/MasterData.Core/DataManager/Exportation/DataExportationWriterFactory.cs
@@ -1,6 +1,5 @@
-#nullable enable
-using System;
-using JJMasterData.Commons.Tasks;
+using System;
+using JJConsulting.MasterData.Storage.Abstractions;
using JJMasterData.Core.DataManager.Exportation.Abstractions;
using JJMasterData.Core.DataManager.Exportation.Configuration;
using JJMasterData.Core.UI.Components;
@@ -11,7 +10,7 @@ namespace JJMasterData.Core.DataManager.Exportation;
public class DataExportationWriterFactory(IServiceProvider serviceProvider)
{
- public event AsyncEventHandler? OnRenderCellAsync;
+ public event EventHandler? OnRenderCell;
private IPdfWriter? GetPdfWriter()
{
@@ -42,7 +41,7 @@ public DataExportationWriterBase GetInstance(JJDataExportation dataExportation)
case ExportFileExtension.TXT:
var textWriter = GetTextWriter();
textWriter.Delimiter = dataExportation.ExportOptions.Delimiter;
- textWriter.OnRenderCellAsync += OnRenderCellAsync;
+ textWriter.OnRenderCell += OnRenderCell;
writer = (DataExportationWriterBase)textWriter;
break;
@@ -51,7 +50,7 @@ public DataExportationWriterBase GetInstance(JJDataExportation dataExportation)
var excelWriter = GetExcelWriter();
excelWriter.ShowRowStriped = dataExportation.ShowRowStriped;
excelWriter.ShowBorder = dataExportation.ShowBorder;
- excelWriter.OnRenderCellAsync += OnRenderCellAsync;
+ excelWriter.OnRenderCell += OnRenderCell;
writer = (DataExportationWriterBase)excelWriter;
@@ -64,7 +63,7 @@ public DataExportationWriterBase GetInstance(JJDataExportation dataExportation)
pdfWriter.ShowRowStriped = dataExportation.ShowRowStriped;
pdfWriter.ShowBorder = dataExportation.ShowBorder;
- pdfWriter.OnRenderCellAsync += OnRenderCellAsync;
+ pdfWriter.OnRenderCell += OnRenderCell;
// ReSharper disable once SuspiciousTypeConversion.Global;
// PdfWriter is dynamic loaded by plugin.
@@ -81,13 +80,15 @@ public DataExportationWriterBase GetInstance(JJDataExportation dataExportation)
return writer;
}
- private static void ConfigureWriter(JJDataExportation dataExportation, DataExportationWriterBase writer)
+ private void ConfigureWriter(JJDataExportation dataExportation, DataExportationWriterBase writer)
{
writer.FormElement = dataExportation.FormElement;
writer.Configuration = dataExportation.ExportOptions;
writer.UserId = dataExportation.UserId;
writer.ProcessOptions = dataExportation.ProcessOptions;
- writer.AbsoluteUri = dataExportation.CurrentContext.Request.AbsoluteUri;
+ writer.FileDownloaderFactory = serviceProvider.GetRequiredService();
+ writer.FileStorage = serviceProvider.GetRequiredService();
+ writer.AbsoluteUri = dataExportation.HttpContextAccessor.HttpContext!.Request.GetAbsoluteUri();
}
diff --git a/src/MasterData.Core/DataManager/Exportation/ExcelWriter.cs b/src/MasterData.Core/DataManager/Exportation/ExcelWriter.cs
index dac7327d2..bcc567e60 100644
--- a/src/MasterData.Core/DataManager/Exportation/ExcelWriter.cs
+++ b/src/MasterData.Core/DataManager/Exportation/ExcelWriter.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable disable warnings
+using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
@@ -9,14 +10,11 @@
using JJMasterData.Commons.Data.Entity.Models;
using JJMasterData.Commons.Data.Entity.Repository;
using JJMasterData.Commons.Data.Entity.Repository.Abstractions;
-using JJMasterData.Commons.Security.Cryptography.Abstractions;
-using JJMasterData.Commons.Tasks;
using JJMasterData.Core.Configuration.Options;
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataManager.Exportation.Abstractions;
using JJMasterData.Core.DataManager.Expressions;
using JJMasterData.Core.DataManager.Services;
-using JJMasterData.Core.UI.Components;
using JJMasterData.Core.UI.Events.Args;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
@@ -27,19 +25,16 @@ namespace JJMasterData.Core.DataManager.Exportation;
public class ExcelWriter(
ExpressionsService expressionsService,
DataItemService dataItemService,
- IEncryptionService encryptionService,
IStringLocalizer stringLocalizer,
IOptionsSnapshot options,
ILoggerFactory loggerFactory,
IEntityRepository entityRepository)
- : DataExportationWriterBase(
- encryptionService,
- expressionsService,
+ : DataExportationWriterBase(expressionsService,
stringLocalizer,
options,
loggerFactory.CreateLogger()), IExcelWriter
{
- public event AsyncEventHandler OnRenderCellAsync;
+ public event EventHandler OnRenderCell;
public bool ShowBorder { get; set; }
@@ -175,7 +170,7 @@ private async ValueTask CreateCell(FormElementField field, Dictionary{value}";
else
@@ -184,7 +179,7 @@ private async ValueTask CreateCell(FormElementField field, Dictionary CreateCell(FormElementField field, Dictionary");
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataManager/Exportation/TextWriter.cs b/src/MasterData.Core/DataManager/Exportation/TextWriter.cs
index 1478f06ac..5414c5993 100644
--- a/src/MasterData.Core/DataManager/Exportation/TextWriter.cs
+++ b/src/MasterData.Core/DataManager/Exportation/TextWriter.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable disable warnings
+using System;
using System.IO;
using System.Text;
using System.Threading;
@@ -7,12 +8,9 @@
using JJMasterData.Commons.Data.Entity.Models;
using JJMasterData.Commons.Data.Entity.Repository;
using JJMasterData.Commons.Data.Entity.Repository.Abstractions;
-using JJMasterData.Commons.Security.Cryptography.Abstractions;
-using JJMasterData.Commons.Tasks;
using JJMasterData.Core.Configuration.Options;
using JJMasterData.Core.DataManager.Exportation.Abstractions;
using JJMasterData.Core.DataManager.Expressions;
-using JJMasterData.Core.UI.Components;
using JJMasterData.Core.UI.Events.Args;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
@@ -21,20 +19,17 @@
namespace JJMasterData.Core.DataManager.Exportation;
public class TextWriter(
- IEncryptionService encryptionService,
- ExpressionsService expressionsService,
+ ExpressionsService expressionsService,
IStringLocalizer stringLocalizer,
IOptionsSnapshot options,
ILoggerFactory logger,
IEntityRepository entityRepository)
- : DataExportationWriterBase(
- encryptionService,
- expressionsService,
+ : DataExportationWriterBase(expressionsService,
stringLocalizer,
options,
logger.CreateLogger()), ITextWriter
{
- public event AsyncEventHandler OnRenderCellAsync;
+ public event EventHandler OnRenderCell;
public string Delimiter { get; set; }
public override async Task GenerateDocument(Stream stream, CancellationToken token)
@@ -114,7 +109,7 @@ private async Task GenerateRows(StreamWriter sw, CancellationToken token)
value = cellValue?.ToString();
}
- if (OnRenderCellAsync != null)
+ if (OnRenderCell != null)
{
var args = new GridCellEventArgs
{
@@ -123,7 +118,7 @@ private async Task GenerateRows(StreamWriter sw, CancellationToken token)
Sender = new JJText(value)
};
- await OnRenderCellAsync(this, args);
+ OnRenderCell(this, args);
if(args.HtmlResult != null)
value = args.HtmlResult.ToString();
diff --git a/src/MasterData.Core/DataManager/Expressions/Abstractions/IAsyncExpressionProvider.cs b/src/MasterData.Core/DataManager/Expressions/Abstractions/IAsyncExpressionProvider.cs
index 1a7670545..b73f60597 100644
--- a/src/MasterData.Core/DataManager/Expressions/Abstractions/IAsyncExpressionProvider.cs
+++ b/src/MasterData.Core/DataManager/Expressions/Abstractions/IAsyncExpressionProvider.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
diff --git a/src/MasterData.Core/DataManager/Expressions/Abstractions/ISyncExpressionProvider.cs b/src/MasterData.Core/DataManager/Expressions/Abstractions/ISyncExpressionProvider.cs
index 60a4b8ad1..a66827f47 100644
--- a/src/MasterData.Core/DataManager/Expressions/Abstractions/ISyncExpressionProvider.cs
+++ b/src/MasterData.Core/DataManager/Expressions/Abstractions/ISyncExpressionProvider.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System.Collections.Generic;
namespace JJMasterData.Core.DataManager.Expressions.Abstractions;
diff --git a/src/MasterData.Core/DataManager/Expressions/ExpressionDataAccessCommandFactory.cs b/src/MasterData.Core/DataManager/Expressions/ExpressionDataAccessCommandFactory.cs
index 0ca84311a..948367030 100644
--- a/src/MasterData.Core/DataManager/Expressions/ExpressionDataAccessCommandFactory.cs
+++ b/src/MasterData.Core/DataManager/Expressions/ExpressionDataAccessCommandFactory.cs
@@ -1,5 +1,4 @@
-#nullable enable
-using System;
+using System;
using System.Collections.Generic;
using System.Data;
using JJMasterData.Commons.Data;
diff --git a/src/MasterData.Core/DataManager/Expressions/ExpressionHelper.cs b/src/MasterData.Core/DataManager/Expressions/ExpressionHelper.cs
index 9d92baf86..e6d48778e 100644
--- a/src/MasterData.Core/DataManager/Expressions/ExpressionHelper.cs
+++ b/src/MasterData.Core/DataManager/Expressions/ExpressionHelper.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System.Collections.Generic;
using System.Globalization;
using System.Text;
@@ -15,10 +14,8 @@ public static string ReplaceExpression(string expression, Dictionary doubleValue.ToString("F6", NumberFormatInfo.InvariantInfo),
@@ -27,7 +24,7 @@ public static string ReplaceExpression(string expression, Dictionary value?.ToString() ?? string.Empty
};
- stringBuilder.Replace($"{Begin}{kvp.Key}{End}", encodeValue ? HttpUtility.HtmlEncode(stringValue) : stringValue);
+ stringBuilder.Replace($"{Begin}{key}{End}", encodeValue ? HttpUtility.HtmlEncode(stringValue) : stringValue);
}
return stringBuilder.ToString();
diff --git a/src/MasterData.Core/DataManager/Expressions/ExpressionParser.cs b/src/MasterData.Core/DataManager/Expressions/ExpressionParser.cs
index 7574a5eee..99029aa1c 100644
--- a/src/MasterData.Core/DataManager/Expressions/ExpressionParser.cs
+++ b/src/MasterData.Core/DataManager/Expressions/ExpressionParser.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -8,14 +6,13 @@
using JJMasterData.Commons.Util;
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataManager.Models;
-using JJMasterData.Core.Http.Abstractions;
using JJMasterData.Core.Logging;
using Microsoft.Extensions.Logging;
namespace JJMasterData.Core.DataManager.Expressions;
public sealed class ExpressionParser(
- IHttpContext httpContext,
+ IHttpContextAccessor httpContext,
IMasterDataUser masterDataUser,
ILogger logger)
{
@@ -68,7 +65,7 @@ public sealed class ExpressionParser(
case "isdelete":
return pageState is PageState.Delete ? 1 : 0;
case "fieldname":
- return httpContext.Request.QueryString["fieldName"];
+ return httpContext.HttpContext?.Request.Query["fieldName"].ToString();
case "userid":
return masterDataUser.Id;
case "currentculture":
@@ -92,10 +89,6 @@ public sealed class ExpressionParser(
else
parsedValue = objValue;
}
- else if (httpContext.Session.HasSession() && httpContext.Session.HasKey(field))
- {
- parsedValue = httpContext.Session[field];
- }
else
{
parsedValue = GetClaimValue(field) ?? string.Empty;
@@ -106,6 +99,6 @@ public sealed class ExpressionParser(
private string? GetClaimValue(string claimType)
{
- return httpContext.User?.FindFirst(claimType)?.Value;
+ return httpContext.HttpContext?.User?.FindFirst(claimType)?.Value;
}
}
diff --git a/src/MasterData.Core/DataManager/Expressions/ExpressionsService.cs b/src/MasterData.Core/DataManager/Expressions/ExpressionsService.cs
index 5169fa0b5..f56059cd5 100644
--- a/src/MasterData.Core/DataManager/Expressions/ExpressionsService.cs
+++ b/src/MasterData.Core/DataManager/Expressions/ExpressionsService.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,7 +10,6 @@
using JJMasterData.Core.DataManager.Expressions.Abstractions;
using JJMasterData.Core.DataManager.Expressions.Providers;
using JJMasterData.Core.DataManager.Models;
-using JJMasterData.Core.Extensions;
using JJMasterData.Core.Logging;
using Microsoft.Extensions.Logging;
@@ -58,7 +56,7 @@ private void EncryptValues(Dictionary parsedValues)
foreach (var key in keysToUpdate)
{
- parsedValues[key] = encryptionService.EncryptStringWithUrlEscape(parsedValues[key]!.ToString()!);
+ parsedValues[key] = encryptionService.EncryptString(parsedValues[key]!.ToString()!);
}
}
diff --git a/src/MasterData.Core/DataManager/Expressions/Providers/DefaultExpressionProvider.cs b/src/MasterData.Core/DataManager/Expressions/Providers/DefaultExpressionProvider.cs
index 5bfca3ecd..461031356 100644
--- a/src/MasterData.Core/DataManager/Expressions/Providers/DefaultExpressionProvider.cs
+++ b/src/MasterData.Core/DataManager/Expressions/Providers/DefaultExpressionProvider.cs
@@ -1,8 +1,5 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.Threading.Tasks;
using JJMasterData.Core.Configuration.Options;
using JJMasterData.Core.DataManager.Expressions.Abstractions;
@@ -11,6 +8,7 @@
using Microsoft.Extensions.Options;
using NCalc;
using NCalc.Factories;
+using NCalc.Handlers;
namespace JJMasterData.Core.DataManager.Expressions.Providers;
@@ -21,14 +19,6 @@ public sealed class DefaultExpressionProvider(
ILogger logger)
: ISyncExpressionProvider, IAsyncExpressionProvider
{
- private readonly ExpressionContext _expressionContext = options.Value.ExpressionContext with
- {
- StaticParameters = new Dictionary(options.Value.ExpressionContext.StaticParameters, StringComparer.InvariantCultureIgnoreCase)
- {
- ["ServiceProvider"] = serviceProvider
- }
- };
-
public string Prefix => "exp";
public string Title => "Expression";
@@ -38,11 +28,16 @@ public sealed class DefaultExpressionProvider(
{
var parameters = new Dictionary(parsedValues.Count, StringComparer.InvariantCultureIgnoreCase);
var preparedExpression = PrepareExpressionWithParameters(expression, parsedValues, parameters);
+
+ var expressionContext = new ExpressionContext(options.Value.ExpressionContext)
+ {
+ Parameters = new Dictionary(parameters, StringComparer.InvariantCultureIgnoreCase)
+ {
+ ["ServiceProvider"] = serviceProvider
+ }
+ };
- foreach (var parameter in parameters)
- _expressionContext.StaticParameters[parameter.Key] = parameter.Value;
-
- var ncalcExpression = expressionFactory.Create(preparedExpression, _expressionContext);
+ var ncalcExpression = expressionFactory.Create(preparedExpression, options.Value.ExpressionConfiguration, expressionContext);
logger.LogExpression(preparedExpression);
diff --git a/src/MasterData.Core/DataManager/Expressions/Providers/SqlExpressionProvider.cs b/src/MasterData.Core/DataManager/Expressions/Providers/SqlExpressionProvider.cs
index e88ce19f0..4d2186d3f 100644
--- a/src/MasterData.Core/DataManager/Expressions/Providers/SqlExpressionProvider.cs
+++ b/src/MasterData.Core/DataManager/Expressions/Providers/SqlExpressionProvider.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
diff --git a/src/MasterData.Core/DataManager/Expressions/Providers/ValueExpressionProvider.cs b/src/MasterData.Core/DataManager/Expressions/Providers/ValueExpressionProvider.cs
index 32e338ae6..2cfb75e7a 100644
--- a/src/MasterData.Core/DataManager/Expressions/Providers/ValueExpressionProvider.cs
+++ b/src/MasterData.Core/DataManager/Expressions/Providers/ValueExpressionProvider.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -16,7 +15,7 @@ public sealed class ValueExpressionProvider : IAsyncExpressionProvider, ISyncExp
public string Title => "Value";
public object Evaluate(string expression, Dictionary parsedValues)
{
- if (expression.Contains(ExpressionHelper.Begin.ToString()))
+ if (expression.Contains(ExpressionHelper.Begin))
return ExpressionHelper.ReplaceExpression(expression, parsedValues).Trim();
return expression.Trim();
diff --git a/src/MasterData.Core/DataManager/FontAwesomeIconHelper.cs b/src/MasterData.Core/DataManager/FontAwesomeIconHelper.cs
index 20dd8e972..c22c6fb98 100644
--- a/src/MasterData.Core/DataManager/FontAwesomeIconHelper.cs
+++ b/src/MasterData.Core/DataManager/FontAwesomeIconHelper.cs
@@ -1,4 +1,3 @@
-#nullable enable
using JJConsulting.FontAwesome;
using JJMasterData.Commons.Exceptions;
using JJMasterData.Core.DataDictionary.Models;
diff --git a/src/MasterData.Core/DataManager/IO/FormFileContent.cs b/src/MasterData.Core/DataManager/IO/FormFileContent.cs
deleted file mode 100644
index 47a75d536..000000000
--- a/src/MasterData.Core/DataManager/IO/FormFileContent.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace JJMasterData.Core.DataManager.IO;
-
-public class FormFileContent
-{
- public string FileName { get; set; }
- public byte[] Bytes { get; init; }
- public long Length { get; set;}
- public DateTime LastWriteTime { get; set; }
-}
\ No newline at end of file
diff --git a/src/MasterData.Core/DataManager/IO/FormFileManager.cs b/src/MasterData.Core/DataManager/IO/FormFileManager.cs
deleted file mode 100644
index a3211bcc6..000000000
--- a/src/MasterData.Core/DataManager/IO/FormFileManager.cs
+++ /dev/null
@@ -1,312 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using JJMasterData.Commons.Exceptions;
-using JJMasterData.Commons.Util;
-using JJMasterData.Core.DataManager.Models;
-using JJMasterData.Core.Http.Abstractions;
-using JJMasterData.Core.UI.Events.Args;
-using Microsoft.Extensions.Localization;
-using Microsoft.Extensions.Logging;
-
-namespace JJMasterData.Core.DataManager.IO;
-
-public class FormFileManager(string memoryFilesSessionName,
- IHttpContext httpContext,
- IStringLocalizer stringLocalizer,
- ILogger logger)
-{
- public event EventHandler OnBeforeCreateFile;
- public event EventHandler OnBeforeDeleteFile;
- public event EventHandler OnBeforeRenameFile;
-
- ///
- /// Session variable name
- ///
- private string MemoryFilesSessionName { get; } = $"{memoryFilesSessionName}_files";
-
- ///
- /// Always apply changes from files on disk,
- /// if it is false, keep it in memory
- /// Default: true
- ///
- public bool AutoSave { get; set; } = true;
-
- ///
- /// Full Directory Path.
- /// (Optional) If the path is not given, all files will be stored in the session.
- ///
- ///
- /// The path is OS agnostic, you can use for example C:\Temp\Files\ or /home/gumbarros/Documents/Files,
- /// but beware where you're deploying your application.
- ///
- public string FolderPath { get; set; }
-
- public List MemoryFiles
- {
- get => httpContext.Session.GetSessionValue>(MemoryFilesSessionName);
- set => httpContext.Session.SetSessionValue(MemoryFilesSessionName, value);
- }
-
- public List GetFiles()
- {
- List files = null;
-
- if (!AutoSave || string.IsNullOrEmpty(FolderPath))
- files = MemoryFiles;
-
- return files ?? GetPhysicalFiles();
- }
-
- public void RenameFile(string currentName, string newName)
- {
- if (string.IsNullOrEmpty(currentName))
- throw new ArgumentNullException(nameof(currentName));
-
- if (string.IsNullOrWhiteSpace(newName))
- throw new ArgumentNullException(stringLocalizer["Required file name"]);
-
- if (!FileIO.GetFileNameExtension(currentName).Equals(FileIO.GetFileNameExtension(newName)))
- throw new JJMasterDataException(stringLocalizer["The file extension must remain the same"]);
-
- var files = GetFiles();
- if (files.Exists(x => x.Content.FileName.Equals(newName)))
- throw new JJMasterDataException(stringLocalizer["A file with the name {0} already exists", newName]);
-
- if (OnBeforeRenameFile != null)
- {
- var args = new FormRenameFileEventArgs(currentName, newName);
- OnBeforeRenameFile.Invoke(this, args);
-
- if (!string.IsNullOrEmpty(args.ErrorMessage))
- throw new JJMasterDataException(args.ErrorMessage);
- }
-
- if (AutoSave && !string.IsNullOrEmpty(FolderPath))
- {
- File.Move(Path.Combine(FolderPath,currentName), Path.Combine(FolderPath, newName));
- }
- else
- {
- var file = files.Find(x => x.Content.FileName.Equals(currentName));
- if (file == null)
- throw new JJMasterDataException(stringLocalizer["file {0} not found!", currentName]);
-
- files.Remove(file);
-
- file.Content.FileName = newName;
- file.OldName ??= currentName;
-
- file.IsRenamed = true;
- files.Add(file);
-
- MemoryFiles = files;
- }
- }
-
- public FormFileInfo GetFile(string fileName)
- {
- var files = GetFiles();
- var file = files.Find(x => fileName.Equals(x.Content.FileName) || fileName.Equals(x.OldName));
-
- return file;
- }
-
- public string GetFilePath(string fileName)
- {
- return Path.Combine(FolderPath, fileName);
- }
-
- public void CreateFile(FormFileContent fileContent, bool replaceIfExists)
- {
- if (fileContent == null)
- throw new ArgumentNullException(nameof(fileContent));
-
- string fileName = fileContent.FileName;
-
- if (OnBeforeCreateFile != null)
- {
- var args = new FormUploadFileEventArgs(fileContent);
- OnBeforeCreateFile.Invoke(this, args);
- string errorMessage = args.ErrorMessage;
-
- if (!string.IsNullOrEmpty(errorMessage))
- {
- var exception = new JJMasterDataException(errorMessage);
- logger.LogError(exception,"Error OnBeforeCreateFile");
- throw exception;
- }
-
- }
-
- if (replaceIfExists && CountFiles() > 0)
- DeleteAll();
-
- if (fileName?.LastIndexOf("\\") > 0)
- // ReSharper disable once ReplaceSubstringWithRangeIndexer
- fileName = fileName.Substring(fileName.LastIndexOf("\\", StringComparison.Ordinal) + 1);
-
- if (AutoSave && !string.IsNullOrEmpty(FolderPath))
- {
- SavePhysicalFile(fileContent);
- }
- else
- {
- var files = GetFiles();
- var currentFile = files.Find(x => x.Content.FileName.Equals(fileName));
- if (currentFile == null)
- {
- var file = new FormFileInfo
- {
- Content = fileContent
- };
- files.Add(file);
- }
- else
- {
- currentFile.Content = fileContent;
- currentFile.Deleted = false;
- }
-
- MemoryFiles = files;
- }
- }
-
- public void DeleteFile(string fileName)
- {
- if (OnBeforeDeleteFile != null)
- {
- var args = new FormDeleteFileEventArgs(fileName);
- OnBeforeDeleteFile.Invoke(this, args);
-
- if (!string.IsNullOrEmpty(args.ErrorMessage))
- {
- var exception = new JJMasterDataException(args.ErrorMessage);
- logger.LogError(exception, "Error OnBeforeDeleteFile");
- throw exception;
- }
- }
-
- if (AutoSave && !string.IsNullOrEmpty(FolderPath))
- {
- File.Delete(Path.Combine(FolderPath, fileName));
- }
- else
- {
- var files = GetFiles();
- var file = files.Find(x => x.Content.FileName.Equals(fileName));
- if (file != null)
- {
- if (!file.IsInMemory)
- file.Deleted = true;
- else
- files.Remove(file);
- }
-
- MemoryFiles = files;
- }
- }
-
- public void DeleteAll()
- {
- if (!string.IsNullOrEmpty(FolderPath))
- {
- if (Directory.Exists(FolderPath))
- Directory.Delete(FolderPath, true);
- }
-
- MemoryFiles = null;
- }
-
- public int CountFiles()
- {
- var listFiles = GetFiles();
- return listFiles.Count(x => !x.Deleted);
- }
-
- public void SaveMemoryFiles(string folderPath, bool deleteExistingFiles = false)
- {
- if (string.IsNullOrEmpty(folderPath))
- throw new ArgumentNullException(nameof(folderPath));
-
- if (MemoryFiles == null)
- return;
-
- if (!Directory.Exists(folderPath))
- Directory.CreateDirectory(folderPath);
-
- FolderPath = folderPath;
-
- if (deleteExistingFiles)
- {
- foreach (var filePath in Directory.GetFiles(FolderPath))
- File.Delete(filePath);
- }
-
- foreach (var file in MemoryFiles)
- {
- string fileName = file.Content.FileName;
- if (file.Deleted)
- {
- string filename = string.IsNullOrEmpty(file.OldName) ? fileName : file.OldName;
- File.Delete(folderPath + filename);
- }
- else if (!string.IsNullOrEmpty(file.OldName) && !file.IsInMemory)
- {
- File.Move(folderPath + file.OldName, folderPath + fileName);
- }
- else if (file.Content.Bytes != null && file.IsInMemory)
- {
- SavePhysicalFile(file.Content);
- }
- }
-
- MemoryFiles = null;
- }
-
- private List GetPhysicalFiles()
- {
- var formFileInfoList = new List();
- if (string.IsNullOrEmpty(FolderPath))
- return formFileInfoList;
-
- var directory = new DirectoryInfo(FolderPath);
- if (directory.Exists)
- {
- var files = directory.GetFiles();
- foreach (var file in files)
- {
- formFileInfoList.Add(new FormFileInfo
- {
- Content =
- {
- FileName = file.Name,
- Length = file.Length,
- LastWriteTime = file.LastWriteTime,
- }
- });
- }
- }
- return formFileInfoList;
- }
-
- private void SavePhysicalFile(FormFileContent file)
- {
- if (file == null)
- throw new ArgumentNullException(nameof(file));
-
- if (string.IsNullOrEmpty(FolderPath))
- throw new ArgumentNullException(nameof(FolderPath));
-
- if (!Directory.Exists(FolderPath))
- Directory.CreateDirectory(FolderPath);
-
- var fileFullName = Path.Combine(FolderPath, file.FileName);
- using var ms = new MemoryStream(file.Bytes);
- using var fileStream = File.Create(fileFullName);
- ms.Seek(0, SeekOrigin.Begin);
- ms.CopyTo(fileStream);
- fileStream.Close();
- }
-}
diff --git a/src/MasterData.Core/DataManager/IO/FormFileManagerFactory.cs b/src/MasterData.Core/DataManager/IO/FormFileManagerFactory.cs
deleted file mode 100644
index e578a07a9..000000000
--- a/src/MasterData.Core/DataManager/IO/FormFileManagerFactory.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using JJMasterData.Core.Http.Abstractions;
-using Microsoft.Extensions.Localization;
-using Microsoft.Extensions.Logging;
-
-namespace JJMasterData.Core.DataManager.IO;
-
-public class FormFileManagerFactory(IHttpContext httpContext, IStringLocalizer stringLocalizer, ILoggerFactory loggerFactory)
-{
-
- public FormFileManager Create(string memoryFilesSessionName)
- {
- return new FormFileManager(memoryFilesSessionName, httpContext, stringLocalizer,
- loggerFactory.CreateLogger());
- }
-}
\ No newline at end of file
diff --git a/src/MasterData.Core/DataManager/IO/FormFilePathBuilder.cs b/src/MasterData.Core/DataManager/IO/FormFilePathBuilder.cs
deleted file mode 100644
index b2e42409d..000000000
--- a/src/MasterData.Core/DataManager/IO/FormFilePathBuilder.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using JJMasterData.Commons.Util;
-using JJMasterData.Core.DataDictionary.Models;
-
-namespace JJMasterData.Core.DataManager.IO;
-
-public class FormFilePathBuilder(FormElement formElement)
-{
- public string GetFolderPath(FormElementField field, Dictionary formValues)
- {
- if (field.DataFile == null)
- throw new ArgumentException(@$"{nameof(FormElementField.DataFile)} not defined.", field.Name);
-
- //Pks concat with underline
- var pkValues = DataHelper.ParsePkValues(formElement, formValues, '_');
-
- //Path configured in the dictionary
- var path = field.DataFile.FolderPath;
-
- if (string.IsNullOrEmpty(path))
- throw new ArgumentException(@$"{nameof(FormElementField.DataFile.FolderPath)} cannot be empty.", field.Name);
-
- var separator = Path.DirectorySeparatorChar;
-
- if (path.Contains("{app.path}"))
- {
- var appPath = FileIO.GetApplicationPath().TrimEnd(separator);
-
- path = path.Replace("{app.path}", appPath);
- }
-
- path = Path.Combine(path, pkValues);
-
- if (!path.EndsWith(separator.ToString()))
- path += separator;
-
- return path;
- }
-}
diff --git a/src/MasterData.Core/DataManager/IO/FormFileService.cs b/src/MasterData.Core/DataManager/IO/FormFileService.cs
deleted file mode 100644
index 70b96b9ee..000000000
--- a/src/MasterData.Core/DataManager/IO/FormFileService.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Collections.Generic;
-using JJMasterData.Core.DataDictionary.Models;
-
-namespace JJMasterData.Core.DataManager.IO;
-
-public class FormFileService(FormFileManagerFactory formFileManagerFactory)
-{
- public void SaveFormMemoryFiles(FormElement formElement, Dictionary primaryKeys)
- {
- var uploadFields = formElement.Fields.FindAll(x => x.Component == FormComponent.File);
- if (uploadFields.Count == 0)
- return;
-
- var pathBuilder = new FormFilePathBuilder(formElement);
- foreach (var field in uploadFields)
- {
- var folderPath = pathBuilder.GetFolderPath(field, primaryKeys);
- var manager = formFileManagerFactory.Create($"{field.Name}-upload-view-files");
-
- manager.SaveMemoryFiles(folderPath, deleteExistingFiles: !field.DataFile.MultipleFile);
- }
- }
-
- public void DeleteFiles(FormElement formElement, Dictionary primaryKeys)
- {
- var fileFields = formElement.Fields.FindAll(x => x.Component == FormComponent.File);
- if (fileFields.Count == 0)
- return;
-
- foreach (var field in fileFields)
- {
- var manager = formFileManagerFactory.Create($"{field.Name}-upload-view-files");
- manager.FolderPath = new FormFilePathBuilder(formElement).GetFolderPath(field, primaryKeys);
- manager.DeleteAll();
- }
- }
-}
\ No newline at end of file
diff --git a/src/MasterData.Core/DataManager/Importation/DataImportationDto.cs b/src/MasterData.Core/DataManager/Importation/DataImportationDto.cs
index 51f9263c5..ce425bcc6 100644
--- a/src/MasterData.Core/DataManager/Importation/DataImportationDto.cs
+++ b/src/MasterData.Core/DataManager/Importation/DataImportationDto.cs
@@ -1,4 +1,5 @@
-
+#nullable disable warnings
+
using System.Text.Json.Serialization;
diff --git a/src/MasterData.Core/DataManager/Importation/DataImportationWorker.cs b/src/MasterData.Core/DataManager/Importation/DataImportationWorker.cs
index 829b649a5..06d6951ce 100644
--- a/src/MasterData.Core/DataManager/Importation/DataImportationWorker.cs
+++ b/src/MasterData.Core/DataManager/Importation/DataImportationWorker.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable disable warnings
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
@@ -66,14 +67,8 @@ public class DataImportationWorker(
internal FormService FormService { get; } = formService;
-#if NETFRAMEWORK
- private System.Web.HttpContext HttpContext { get; } = System.Web.HttpContext.Current;
-#endif
public async Task RunWorkerAsync(CancellationToken token)
{
-#if NETFRAMEWORK
- System.Web.HttpContext.Current = HttpContext;
-#endif
var currentProcess = new DataImportationReporter(StringLocalizer);
try
{
@@ -308,4 +303,4 @@ private async Task> SaveRowValues(Dictionary coreOptions)
: IMasterDataUser
{
- public string Id { get; set; } = httpContext.User?.GetUserId(coreOptions.Value.UserIdClaimType);
+ public string Id { get; set; } = httpContext.HttpContext?.User.GetUserId(coreOptions.Value.UserIdClaimType);
}
\ No newline at end of file
diff --git a/src/MasterData.Core/DataManager/Models/DataContext.cs b/src/MasterData.Core/DataManager/Models/DataContext.cs
index 6414e38da..1795f9efc 100644
--- a/src/MasterData.Core/DataManager/Models/DataContext.cs
+++ b/src/MasterData.Core/DataManager/Models/DataContext.cs
@@ -1,8 +1,4 @@
-#nullable enable
-
-using JJMasterData.Core.Http.Abstractions;
-
-namespace JJMasterData.Core.DataManager.Models;
+namespace JJMasterData.Core.DataManager.Models;
public class DataContext
{
@@ -18,11 +14,16 @@ public DataContext()
{
}
- public DataContext(IHttpRequest request, DataContextSource source, string? userId)
+ public DataContext(IHttpContextAccessor request, DataContextSource source, string? userId)
+ : this(request.HttpContext?.Request, source, userId)
+ {
+ }
+
+ public DataContext(HttpRequest? request, DataContextSource source, string? userId)
{
Source = source;
UserId = userId;
- IpAddress = request.UserHostAddress;
- BrowserInfo = request.UserAgent;
+ IpAddress = request?.HttpContext.Connection.RemoteIpAddress?.ToString();
+ BrowserInfo = request?.Headers.UserAgent.ToString();
}
-}
\ No newline at end of file
+}
diff --git a/src/MasterData.Core/DataManager/Models/DataItemResult.cs b/src/MasterData.Core/DataManager/Models/DataItemResult.cs
index b5050ffc8..bce00c602 100644
--- a/src/MasterData.Core/DataManager/Models/DataItemResult.cs
+++ b/src/MasterData.Core/DataManager/Models/DataItemResult.cs
@@ -1,7 +1,4 @@
-#nullable enable
-
-
-using System.Text.Json.Serialization;
+using System.Text.Json.Serialization;
namespace JJMasterData.Core.DataManager.Models;
diff --git a/src/MasterData.Core/DataManager/Models/DataQuery.cs b/src/MasterData.Core/DataManager/Models/DataQuery.cs
index cc780f1b9..1cccf51a4 100644
--- a/src/MasterData.Core/DataManager/Models/DataQuery.cs
+++ b/src/MasterData.Core/DataManager/Models/DataQuery.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System;
+using System;
namespace JJMasterData.Core.DataManager.Models;
diff --git a/src/MasterData.Core/DataManager/Models/FormFileInfo.cs b/src/MasterData.Core/DataManager/Models/FormFileInfo.cs
deleted file mode 100644
index 361bb137b..000000000
--- a/src/MasterData.Core/DataManager/Models/FormFileInfo.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using JJMasterData.Core.DataManager.IO;
-
-namespace JJMasterData.Core.DataManager.Models;
-
-public class FormFileInfo
-{
- private FormFileContent _content;
-
- public FormFileContent Content
- {
- get => _content ??= new FormFileContent();
- set => _content = value;
- }
-
- public FormFileInfo()
- {
-
- }
- public bool IsRenamed { get; set; }
- public bool Deleted { get; set; }
-
- public string OldName { get; set; }
-
- public string FileName => Content.FileName ?? OldName;
-
- public bool IsInMemory => Content.Bytes != null;
-}
diff --git a/src/MasterData.Core/DataManager/Models/FormLetter.cs b/src/MasterData.Core/DataManager/Models/FormLetter.cs
index 0bad08e9d..d042c8b1e 100644
--- a/src/MasterData.Core/DataManager/Models/FormLetter.cs
+++ b/src/MasterData.Core/DataManager/Models/FormLetter.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System.Collections.Generic;
namespace JJMasterData.Core.DataManager.Models;
diff --git a/src/MasterData.Core/DataManager/Models/FormStateData.cs b/src/MasterData.Core/DataManager/Models/FormStateData.cs
index 508778aaa..bc21ac382 100644
--- a/src/MasterData.Core/DataManager/Models/FormStateData.cs
+++ b/src/MasterData.Core/DataManager/Models/FormStateData.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System.Collections.Generic;
+using System.Collections.Generic;
using JJMasterData.Core.DataDictionary.Models;
namespace JJMasterData.Core.DataManager.Models;
diff --git a/src/MasterData.Core/DataManager/Models/UrlRedirectModel.cs b/src/MasterData.Core/DataManager/Models/UrlRedirectModel.cs
index f00e8aacf..6e5d3207f 100644
--- a/src/MasterData.Core/DataManager/Models/UrlRedirectModel.cs
+++ b/src/MasterData.Core/DataManager/Models/UrlRedirectModel.cs
@@ -1,8 +1,5 @@
-#nullable enable
-
using System.Text.Json.Serialization;
using JJConsulting.Html.Bootstrap.Models;
-using JJMasterData.Core.DataDictionary.Models;
namespace JJMasterData.Core.DataManager.Models;
diff --git a/src/MasterData.Core/DataManager/Services/Abstractions/IRuleExecutor.cs b/src/MasterData.Core/DataManager/Services/Abstractions/IRuleExecutor.cs
new file mode 100644
index 000000000..401ea387e
--- /dev/null
+++ b/src/MasterData.Core/DataManager/Services/Abstractions/IRuleExecutor.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using JJMasterData.Core.DataDictionary.Models;
+
+namespace JJMasterData.Core.DataManager.Services.Abstractions;
+
+public interface IRuleExecutor
+{
+ RuleLanguage Language { get; }
+
+ Task> ExecuteAsync(
+ FormElement formElement,
+ FormElementRule rule,
+ Dictionary values);
+}
diff --git a/src/MasterData.Core/DataManager/Services/AuditLogService.cs b/src/MasterData.Core/DataManager/Services/AuditLogService.cs
index b4e79edac..4b80e95cf 100644
--- a/src/MasterData.Core/DataManager/Services/AuditLogService.cs
+++ b/src/MasterData.Core/DataManager/Services/AuditLogService.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable disable warnings
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -32,7 +33,7 @@ public class AuditLogService(
public const string DicBrowser = "browser";
public const string DicJson = "json";
- public async Task LogAsync(Element element,DataContext dataContext, Dictionary formValues, CommandOperation action)
+ public async Task LogAsync(Element element,DataContext dataContext, Dictionary formValues, CommandOperation action)
{
var values = new Dictionary
{
diff --git a/src/MasterData.Core/DataManager/Services/DataItemService.cs b/src/MasterData.Core/DataManager/Services/DataItemService.cs
index 6aaab04ab..1b5404c36 100644
--- a/src/MasterData.Core/DataManager/Services/DataItemService.cs
+++ b/src/MasterData.Core/DataManager/Services/DataItemService.cs
@@ -1,5 +1,4 @@
-#nullable enable
-
+#nullable disable warnings
using System;
using System.Collections.Generic;
using System.Data;
diff --git a/src/MasterData.Core/DataManager/Services/ElementFileService.cs b/src/MasterData.Core/DataManager/Services/ElementFileService.cs
index ad9d7fd6a..c7d9004be 100644
--- a/src/MasterData.Core/DataManager/Services/ElementFileService.cs
+++ b/src/MasterData.Core/DataManager/Services/ElementFileService.cs
@@ -1,46 +1,68 @@
-#if NET
-
-#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using JJConsulting.MasterData.Storage.Abstractions;
using JJMasterData.Commons.Data.Entity.Models;
using JJMasterData.Commons.Data.Entity.Repository.Abstractions;
+using JJMasterData.Commons.Storage;
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataDictionary.Repository.Abstractions;
-using JJMasterData.Core.DataManager.IO;
-using Microsoft.AspNetCore.Http;
namespace JJMasterData.Core.DataManager.Services;
-public class ElementFileService(IDataDictionaryRepository dictionaryRepository, IEntityRepository entityRepository)
+public class ElementFileService(
+ IDataDictionaryRepository dictionaryRepository,
+ IEntityRepository entityRepository,
+ IFileStorage fileStorage,
+ FileValidationService fileValidationService)
{
- public async Task GetElementFileAsync(string elementName, string pkValues, string fieldName, string? fileName)
+ public async Task SaveFileAsync(string folderPath, IFormFile file, bool overwrite = true, string? allowedTypes = null)
{
- var formElement = await dictionaryRepository.GetFormElementAsync(elementName);
+ var fileName = Path.GetFileName(file.FileName);
+ fileValidationService.Validate(file, allowedTypes);
+ var fullPath = FileStoragePath.Combine(folderPath, fileName);
+ await using var uploadStream = file.OpenReadStream();
+ await fileStorage.SaveAsync(fullPath, uploadStream, overwrite);
+ }
+
+ public async Task DeleteFileAsync(string folderPath, string fileName)
+ {
fileName = Path.GetFileName(fileName);
+ var fullPath = FileStoragePath.Combine(folderPath, fileName);
+ await fileStorage.DeleteAsync(fullPath);
+ }
- var field = formElement.Fields.First(f => f.Name == fieldName);
+ public async Task RenameFileAsync(string folderPath, string oldName, string newName)
+ {
+ oldName = Path.GetFileName(oldName);
+ newName = Path.GetFileName(newName);
+ fileValidationService.ValidateFileName(newName);
- var builder = new FormFilePathBuilder(formElement);
+ var oldFullPath = FileStoragePath.Combine(folderPath, oldName);
+ var newFullPath = FileStoragePath.Combine(folderPath, newName);
+ await fileStorage.MoveAsync(oldFullPath, newFullPath);
+ }
- var path = builder.GetFolderPath(field, DataHelper.GetPkValues(formElement, pkValues, ','));
+ public async Task GetElementFileAsync(string elementName, string pkValues, string fieldName, string? fileName)
+ {
+ var formElement = await dictionaryRepository.GetFormElementAsync(elementName);
+
+ fileName = Path.GetFileName(fileName);
+
+ var field = formElement.Fields.First(f => f.Name == fieldName);
+ var folderPath = FileStoragePath.GetFolderPath(formElement, field, DataHelper.GetPkValues(formElement, pkValues, ',')!);
- string? file;
if (string.IsNullOrEmpty(fileName))
- file = Directory.GetFiles(path).FirstOrDefault();
- else
- file = Directory.GetFiles(path).FirstOrDefault(f => f.EndsWith(fileName));
+ fileName = (await fileStorage.ListAsync(folderPath)).FirstOrDefault()?.FileName;
- if (file == null)
+ if (string.IsNullOrEmpty(fileName))
return null;
- var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
-
- return fileStream;
+ var fullPath = FileStoragePath.Combine(folderPath, fileName);
+ return await fileStorage.OpenReadAsync(fullPath);
}
@@ -56,6 +78,7 @@ public async Task SetElementFileAsync(
throw new UnauthorizedAccessException();
var field = formElement.Fields.First(f => f.Name == fieldName);
+ fileValidationService.Validate(file, field.DataFile?.AllowedTypes);
await SetPhysicalFileAsync(formElement, field, pkValues, file);
@@ -96,38 +119,16 @@ private async Task SetEntityFileAsync(FormElement formElement, FormElementField
await entityRepository.SetValuesAsync(formElement, values);
}
- private static async Task SetPhysicalFileAsync(
+ private async Task SetPhysicalFileAsync(
FormElement formElement,
FormElementField field,
string pkValues,
IFormFile file)
{
- var builder = new FormFilePathBuilder(formElement);
-
var hashValues = DataHelper.GetPkValues(formElement, pkValues, ',');
-
- var path = builder.GetFolderPath(field, hashValues);
-
- if (!Directory.Exists(path))
- Directory.CreateDirectory(path);
+ var folderPath = FileStoragePath.GetFolderPath(formElement, field, hashValues!);
- var fileName = Path.GetFileName(file.FileName);
-
- if (field.DataFile!.MultipleFile)
- {
- foreach (var fileInfo in new DirectoryInfo(path).EnumerateFiles())
- {
- if (fileInfo.Name == fileName)
- {
- fileInfo.Delete();
- }
- }
- }
-
- await using var fileStream =
- new FileStream(Path.Combine(path, fileName), FileMode.OpenOrCreate, FileAccess.ReadWrite);
-
- await file.CopyToAsync(fileStream);
+ await SaveFileAsync(folderPath, file, true, field.DataFile?.AllowedTypes);
}
public async Task DeleteFileAsync(string elementName, string fieldName, string pkValues, string fileName)
@@ -141,24 +142,16 @@ public async Task DeleteFileAsync(string elementName, string fieldName, string p
fileName = Path.GetFileName(fileName);
- DeletePhysicalFile(formElement, field, pkValues, fileName);
+ await DeletePhysicalFileAsync(formElement, field, pkValues, fileName);
await DeleteEntityFileAsync(formElement, field, pkValues, fileName);
}
- private static void DeletePhysicalFile(FormElement formElement, FormElementField field, string pkValues, string fileName)
+ private async Task DeletePhysicalFileAsync(FormElement formElement, FormElementField field, string pkValues, string fileName)
{
- var builder = new FormFilePathBuilder(formElement);
-
- var path = builder.GetFolderPath(field, DataHelper.GetPkValues(formElement, pkValues, ','));
-
fileName = Path.GetFileName(fileName);
-
- var filePath = Path.Combine(path, fileName);
-
- if (File.Exists(filePath))
- File.Delete(filePath);
- else
- throw new KeyNotFoundException("File not found");
+ var folderPath = FileStoragePath.GetFolderPath(formElement, field, DataHelper.GetPkValues(formElement, pkValues, ',')!);
+
+ await DeleteFileAsync(folderPath, fileName);
}
private async Task DeleteEntityFileAsync(Element element, FormElementField field, string pkValues, string fileName)
@@ -173,8 +166,9 @@ private async Task DeleteEntityFileAsync(Element element, FormElementField field
if (field.DataFile!.MultipleFile)
{
var currentFiles = values[field.Name]!.ToString()!.Split(',').ToList();
-
- if (currentFiles.Contains(fileName))
+
+ var removed = currentFiles.Remove(fileName);
+ if (removed)
{
currentFiles.Remove(fileName);
values[field.Name] = string.Join(",", currentFiles);
@@ -201,23 +195,14 @@ public async Task RenameFileAsync(string elementName, string fieldName, string p
oldName = Path.GetFileName(oldName);
newName = Path.GetFileName(newName);
- RenamePhysicalFile(formElement, field, pkValues, oldName, newName);
+ await RenamePhysicalFileAsync(formElement, field, pkValues, oldName, newName);
await RenameEntityFileAsync(formElement,field, pkValues, oldName, newName);
}
- private static void RenamePhysicalFile(FormElement formElement, FormElementField field, string pkValues, string oldName, string newName)
+ private async Task RenamePhysicalFileAsync(FormElement formElement, FormElementField field, string pkValues, string oldName, string newName)
{
- var builder = new FormFilePathBuilder(formElement);
-
- var path = builder.GetFolderPath(field, DataHelper.GetPkValues(formElement, pkValues, ','));
-
- var oldFilePath = Path.Combine(path, oldName);
- var newFilePath = Path.Combine(path, newName);
-
- if (File.Exists(oldFilePath))
- File.Move(oldFilePath, newFilePath);
- else
- throw new KeyNotFoundException("File not found");
+ var folderPath = FileStoragePath.GetFolderPath(formElement, field, DataHelper.GetPkValues(formElement, pkValues, ',')!);
+ await RenameFileAsync(folderPath, oldName, newName);
}
private async Task RenameEntityFileAsync(FormElement formElement, FormElementField field, string pkValues, string oldName,
@@ -246,4 +231,3 @@ private async Task RenameEntityFileAsync(FormElement formElement, FormElementFie
await entityRepository.SetValuesAsync(formElement, values);
}
}
-#endif
\ No newline at end of file
diff --git a/src/MasterData.Core/DataManager/Services/ElementMapService.cs b/src/MasterData.Core/DataManager/Services/ElementMapService.cs
index 303397f19..6e71a9a64 100644
--- a/src/MasterData.Core/DataManager/Services/ElementMapService.cs
+++ b/src/MasterData.Core/DataManager/Services/ElementMapService.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System.Collections.Generic;
using System.Threading.Tasks;
using JJMasterData.Commons.Data.Entity.Repository;
diff --git a/src/MasterData.Core/DataManager/Services/FieldFormattingService.cs b/src/MasterData.Core/DataManager/Services/FieldFormattingService.cs
index 873ed7cb5..9933803e4 100644
--- a/src/MasterData.Core/DataManager/Services/FieldFormattingService.cs
+++ b/src/MasterData.Core/DataManager/Services/FieldFormattingService.cs
@@ -35,10 +35,7 @@ public async ValueTask FormatGridValueAsync(
case FormComponent.Percentage:
stringValue = GetNumericValueAsString(field, value, $"N{field.NumberOfDecimalPlaces}");
if (!string.IsNullOrEmpty(stringValue))
- {
- stringValue += "%";
- }
-
+ stringValue += '%';
break;
case FormComponent.Number:
case FormComponent.Slider:
@@ -51,12 +48,12 @@ public async ValueTask FormatGridValueAsync(
when field.DataItem is { GridBehavior: not DataItemGridBehavior.Id }:
var allowOnlyNumerics = field.DataType is FieldType.Int or FieldType.Float or FieldType.Decimal;
stringValue = await lookupService.GetDescriptionAsync(field.DataItem.ElementMap!, formStateData,
- value.ToString(), allowOnlyNumerics);
+ value.ToString(), allowOnlyNumerics) ?? string.Empty;
break;
case FormComponent.CheckBox:
stringValue = StringManager.ParseBool(value) ? stringLocalizer["Yes"] : stringLocalizer["No"];
break;
- case FormComponent.Search or FormComponent.ComboBox or FormComponent.RadioButtonGroup
+ case FormComponent.Search or FormComponent.ComboBox or FormComponent.RadioButtonGroup
when field.DataItem is { GridBehavior: not DataItemGridBehavior.Id }:
return await dataItemService.GetDescriptionAsync(fieldSelector.FormElement, field, formStateData, value);
default:
@@ -67,10 +64,10 @@ public async ValueTask FormatGridValueAsync(
if (field.EncodeHtml)
stringValue = HttpUtility.HtmlEncode(stringValue);
- return stringValue ?? string.Empty;
+ return stringValue.Trim();
}
- public static string FormatValue(FormElementField field, object value)
+ public static string FormatValue(FormElementField field, object? value)
{
var stringValue = value?.ToString();
if (string.IsNullOrEmpty(stringValue))
@@ -133,7 +130,7 @@ public static string FormatValue(FormElementField field, object value)
return stringValue;
}
- private static string GetNumericValueAsString(FormElementField field, object value, [StringSyntax("NumericFormat")] string decimalFormat)
+ private static string GetNumericValueAsString(FormElementField field, object? value, [StringSyntax("NumericFormat")] string decimalFormat)
{
CultureInfo cultureInfo;
if (field.Attributes.TryGetValue(FormElementField.CultureInfoAttribute, out var cultureInfoName)
@@ -142,24 +139,24 @@ private static string GetNumericValueAsString(FormElementField field, object val
else
cultureInfo = CultureInfo.CurrentUICulture;
- string stringValue = null;
+ string? stringValue = null;
switch (field.DataType)
{
case FieldType.Float:
{
- if (value is double doubleValue || double.TryParse(value.ToString(), out doubleValue))
+ if (value is double doubleValue || double.TryParse(value?.ToString(), out doubleValue))
stringValue = doubleValue.ToString(decimalFormat, cultureInfo);
break;
}
case FieldType.Int:
{
- if (value is int intValue || int.TryParse(value.ToString(), out intValue))
+ if (value is int intValue || int.TryParse(value?.ToString(), out intValue))
stringValue = intValue.ToString("0", cultureInfo);
break;
}
case FieldType.Decimal:
{
- if (value is decimal decimalValue || decimal.TryParse(value.ToString(), out decimalValue))
+ if (value is decimal decimalValue || decimal.TryParse(value?.ToString(), out decimalValue))
stringValue = decimalValue.ToString(decimalFormat, cultureInfo);
break;
}
@@ -167,6 +164,6 @@ private static string GetNumericValueAsString(FormElementField field, object val
throw new JJMasterDataException($"Invalid FieldType for numeric component [{field.Name}]");
}
- return stringValue;
+ return stringValue ?? string.Empty;
}
}
\ No newline at end of file
diff --git a/src/MasterData.Core/DataManager/Services/FieldValidationService.cs b/src/MasterData.Core/DataManager/Services/FieldValidationService.cs
index 0e80d5eb5..00931bb18 100644
--- a/src/MasterData.Core/DataManager/Services/FieldValidationService.cs
+++ b/src/MasterData.Core/DataManager/Services/FieldValidationService.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
+using System.Threading.Tasks;
using JJConsulting.Html;
using JJConsulting.Html.Extensions;
using JJMasterData.Commons.Data.Entity.Models;
@@ -8,6 +10,7 @@
using JJMasterData.Core.DataDictionary.Models;
using JJMasterData.Core.DataManager.Expressions;
using JJMasterData.Core.DataManager.Models;
+using JJMasterData.Core.DataManager.Services.Abstractions;
using Microsoft.Extensions.Localization;
@@ -15,11 +18,29 @@ namespace JJMasterData.Core.DataManager.Services;
public class FieldValidationService(
ExpressionsService expressionsService,
+ IEnumerable validationScriptExecutors,
IStringLocalizer localizer)
{
+ private Dictionary ValidationScriptExecutors { get; } =
+ validationScriptExecutors.ToDictionary(e => e.Language);
+
public Dictionary ValidateFields(
FormElement formElement,
- Dictionary formValues,
+ Dictionary formValues,
+ PageState pageState,
+ bool enableErrorLink)
+ {
+ var valueTask = ValidateFieldsAsync(formElement, formValues, pageState, enableErrorLink);
+
+ if (valueTask.IsCompletedSuccessfully)
+ return valueTask.Result;
+
+ return valueTask.AsTask().GetAwaiter().GetResult();
+ }
+
+ public async ValueTask> ValidateFieldsAsync(
+ FormElement formElement,
+ Dictionary