Browse Source

Merge branch 'dev' into auto-merge/rel-8-0/2326

pull/18396/head
maliming 3 years ago
committed by GitHub
parent
commit
02050ab142
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      README.md
  2. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  3. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json
  4. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json
  5. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json
  6. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en-GB.json
  7. 12
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  8. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json
  9. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
  10. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json
  11. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json
  12. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json
  13. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json
  14. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json
  15. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json
  16. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json
  17. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json
  18. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json
  19. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json
  20. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json
  21. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json
  22. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json
  23. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json
  24. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
  25. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
  26. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  27. 35
      abp_io/README.md
  28. 2
      common.props
  29. 223
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/POST.md
  30. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/account-module-register.png
  31. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/community-talk-2023-8.png
  32. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/cover-image.png
  33. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/identity-users.gif
  34. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/password-complexity-indicators.png
  35. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/suite-master-child-datagrid.png
  36. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/users-page.png
  37. 2
      docs/en/Community-Articles/2023-10-28-EF-Core-8-Primitive-Collections/POST.md
  38. 1
      docs/en/Community-Articles/2023-11-06-Blazor-Fullstack-Web-Ui/Post.md
  39. 0
      docs/en/Community-Articles/2023-11-17-AOT-Compilation/Post.md
  40. 10
      docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md
  41. BIN
      docs/en/images/book-mastering-abp-framework.png
  42. 10
      docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md
  43. 9
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
  44. 20
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
  45. 8
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Extensibility/WebAssemblyLookupApiRequestService.cs
  46. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  47. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
  48. 12
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js
  49. 1
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  50. 2
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainer.cs
  51. 9
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs
  52. 6
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs
  53. 2
      framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/ExceptionHandling/Localization/en-GB.json
  54. 2
      framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/ExceptionHandling/Localization/en.json
  55. 2
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs
  56. 7
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs
  57. 2
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs
  58. 5
      framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs
  59. 5
      framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs
  60. 2
      framework/test/Volo.Abp.BlobStoring.Tests/Volo/Abp/BlobStoring/BlobContainer_Tests.cs
  61. 4
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json
  62. 4
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/tr.json
  63. 18
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaOptions.cs
  64. 12
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/RandomTextGenerator.cs
  65. 134
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs
  66. 3
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Volo.CmsKit.Public.Web.csproj
  67. 2
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml
  68. 10
      npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.html
  69. 40
      npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.ts
  70. 3
      npm/ng-packs/packages/setting-management/config/src/lib/enums/policy-names.ts
  71. 19
      npm/scripts/validate-versions.ts

10
README.md

@ -42,6 +42,16 @@ Create a new solution:
<img width="500" src="docs/en/images/db-options.png">
## The Book: Mastering ABP Framework
Written by the creator of ABP Framework, this book will help you to gain a complete understanding of the ABP Framework and modern web application development techniques.
* [Buy on Amazon](https://www.amazon.com/gp/product/B097Z2DM8Q)
* [Buy on Packt Publishing](https://www.packtpub.com/product/mastering-abp-framework/9781801079242)
* [More details about the book](https://abp.io/books/mastering-abp-framework)
![book-mastering-abp-framework](docs/en/images/book-mastering-abp-framework.png)
## What ABP Provides?
ABP provides a **full stack developer experience**.

3
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json

@ -560,6 +560,7 @@
"AddSession": "Add Session",
"AddSponsor": "Add Sponsor",
"SponsorLogo": "Sponsor Logo",
"RegistrationUrl": "Registration Url"
"RegistrationUrl": "Registration Url",
"AllowAbpStudioBetaAccess": "Allow ABP Studio Beta Access"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json

@ -577,7 +577,7 @@
"Purchase_TrainingPrice": "سعر التدريب",
"Purchase_OnboardingTraining": "تدريب مباشر على ABP وتطوير تطبيقات الويب",
"TotalDeveloperPrice": "إجمالي سعر المطور",
"Purchase_PricePerDeveloper": "<span>{0} {1}</span> لكل مطور",
"Purchase_PricePerDeveloper": "<span>{0}</span> لكل مطور",
"Purchase_IncludedDeveloperInfo": "{0} {1} يتضمن.",
"Purchase_LicenseExtraDeveloperPurchaseMessage": "رخصة <span class=\"fw-6\">{0} </span> تحتوي على {1} مطور/ين. يمكنك إضافة مطورين إضافيين الآن أو لاحقًا.",
"StartupTemplates_Page_Title": "عارضات بدء التشغيل",
@ -791,6 +791,7 @@
"PrivacyPolicyPageTitle": "سياسة الخصوصية - سياسة ملفات تعريف الارتباط",
"TermsConditionsPageTitle": "الأحكام والشروط",
"TrainingsPageTitle": "حزم تدريب ABP",
"ModulesPageTitle": "وحدات تطبيق ABP سابقة البناء"
"ModulesPageTitle": "وحدات تطبيق ABP سابقة البناء",
"MultipleOrganizationInfo": "شاهد جميع مؤسساتك"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json

@ -405,6 +405,7 @@
"WhatHappensWhenLicenseEndsExplanation6": "Již nelze získat <a href=\"{0}\">prémiovou podporu</a>.",
"WhatHappensWhenLicenseEndsExplanation7": "Pokud chcete i nadále využívat tyto výhody, můžete svou licenci prodloužit (obnovit). Pokud prodloužíte licenci do <strong>{3} dní</strong> po vypršení platnosti licence, budou uplatněny následující slevy: Týmová licence {0}; Obchodní licence {1}; Enterprise Licence {2}.",
"BlazoriseLicense": "Musíme si koupit licenci Blazorise?",
"BlazoriseLicenseExplanation": "Máme dohodu mezi společnostmi Volosoft a Megabit, na základě této dohody je licence Blazorise přibalena k produktům ABP Commercial, proto si naši zákazníci nemusí kupovat další licenci Blazorise."
"BlazoriseLicenseExplanation": "Máme dohodu mezi společnostmi Volosoft a Megabit, na základě této dohody je licence Blazorise přibalena k produktům ABP Commercial, proto si naši zákazníci nemusí kupovat další licenci Blazorise.",
"MultipleOrganizationInfo": "Podívejte se na všechny vaše organizace"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json

@ -386,6 +386,7 @@
"ContinueWithNewOrganization": "Weiter mit einer neuen Organisation",
"RenewLicenseEarly": "Erhalte ich das ganze Jahr, wenn ich meine Lizenz vorzeitig erneuere?",
"RenewLicenseEarylExplanation": "Wenn Sie Ihre Lizenz vor dem Ablaufdatum Ihrer Lizenz erneuern, wird Ihr Lizenzablaufdatum um 1 Jahr verlängert. Wenn Ihre Lizenz beispielsweise am {0}-06-06 abläuft und Sie sie am {0}-01-01 erneuern, ist das neue Ablaufdatum der Lizenz der {1}-06-06.",
"BlackFridayDiscount": "Black Friday Rabatt"
"BlackFridayDiscount": "Black Friday Rabatt",
"MultipleOrganizationInfo": "Alle Ihre Organisationen anzeigen"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en-GB.json

@ -110,6 +110,7 @@
"RenewLicenseEarly": "If I renew my license early, will I get the full year?",
"RenewLicenseEarylExplanation": "When you renew your license before your license expiry date, 1 year will be added to your license expiry date. For example, if your license expires on {0}-06-06 and you renew it on {0}-01-01, your new license expiry date will be {1}-06-06.",
"LicenseTypeNotCorrect": "The license type is not correct!",
"BlackFridayDiscount": "Black Friday Discount"
"BlackFridayDiscount": "Black Friday Discount",
"MultipleOrganizationInfo": "See All Your Organizations"
}
}

12
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -603,7 +603,7 @@
"Purchase_TrainingPrice": "Training Price",
"Purchase_OnboardingTraining": "Onboarding & Web Application Development Live Training",
"TotalDeveloperPrice": "Total Developer Price",
"Purchase_PricePerDeveloper": "<span>{0} {1}</span> per developer",
"Purchase_PricePerDeveloper": "<span>{0}</span> per developer",
"Purchase_IncludedDeveloperInfo": "{0} {1} included.",
"Purchase_LicenseExtraDeveloperPurchaseMessage": "The <span class=\"fw-bold\">{0} License</span> includes {1} developers. You can add additional developers.",
"StartupTemplates_Page_Title": "ABP Startup Templates",
@ -986,8 +986,8 @@
"Summary": "Summary",
"TrainingPack": "Training pack",
"TrainingPackDiscount": "Training pack discount",
"Purchase_OnboardingTraining_Description": "This live training package is valid for a class of 8 students and this discount is only valid when purchased with the new license. <a href=\"{0}\" class=\"text-white\">Learn more <i class=\"fa fa-external-link ms-1\"></i></a>",
"Purchase_Save": "{0}% <span class=\"save ms-1\">Save {1} {2}</span>",
"Purchase_OnboardingTraining_Description": "This live training is valid for a class of 8 students and this discount is only valid when purchased with the new license. <a href=\"{0}\" class=\"text-white\">Learn more <i class=\"fa fa-external-link ms-1\"></i></a>",
"Purchase_Save": "{0}% <span class=\"save ms-1\">Save {1}</span>",
"RemoveBasket": "Remove from basket",
"WhyABPIOPlatform?": "Why <span class=\"gradient-commercial\">ABP.IO Platform</span>?",
"DocumentAim": "This document aims to answer the big question:",
@ -1085,6 +1085,10 @@
"MultipleYearDiscount": "Multiple Year Discount",
"CampaignDiscountText": "Black Friday Discount",
"CampaignDiscountName": "Black Friday",
"CampaignName:BlackFriday": "Black Friday"
"CampaignName:BlackFriday": "Black Friday",
"MultipleOrganizationInfo": "See All Your Organizations",
"AbpStudioBetaAccessInfoTitle": "ABP Studio Beta Access",
"AbpStudioBetaAccessInfoText": "We're thrilled to share with you the <span class=\"text-highlight-white\">beta</span> version of <span class=\"text-highlight-white\">ABP Studio</span>! This release marks a significant milestone in our development journey, and we're eager to gather your feedback to make the application even better.",
"YouAreNotAuthorizedToDownloadStudio": "You are not authorized to download ABP Studio."
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json

@ -386,6 +386,7 @@
"ContinueWithNewOrganization": "Continuar con una nueva organización",
"RenewLicenseEarly": "Si renuevo mi licencia antes, ¿obtendré el año completo?",
"RenewLicenseEarylExplanation": "Cuando renueve su licencia antes de la fecha de vencimiento de su licencia, se agregará 1 año a la fecha de vencimiento de su licencia. Por ejemplo, si su licencia vence el {0} -06-06 y la renueva el {0} -01-01, la fecha de vencimiento de su nueva licencia será {1} -06-06.",
"BlackFridayDiscount": "Descuento de viernes negro"
"BlackFridayDiscount": "Descuento de viernes negro",
"MultipleOrganizationInfo": "Vea todas sus organizaciones"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json

@ -600,7 +600,7 @@
"Purchase_TrainingPrice": "Koulutuksen hinta",
"Purchase_OnboardingTraining": "ABP:n perehdytys ja verkkosovelluskehitys live-koulutus",
"TotalDeveloperPrice": "Kehittäjän kokonaishinta",
"Purchase_PricePerDeveloper": "<span>{0} {1}</span> kehittäjää kohden",
"Purchase_PricePerDeveloper": "<span>{0}</span> kehittäjää kohden",
"Purchase_IncludedDeveloperInfo": "{0} {1} mukana.",
"Purchase_LicenseExtraDeveloperPurchaseMessage": "<span class=\"fw-6\">{0} lisenssi</span> sisältää {1} kehittäjää. Voit lisätä uusia kehittäjiä nyt tai myöhemmin.",
"StartupTemplates_Page_Title": "Käynnistysmallit",
@ -827,6 +827,7 @@
"ExpirationDate": "Viimeinen käyttöpäivä",
"SpringCampaignDiscount": "Kevään kampanja-alennus",
"WhyUseAbpIoPlatform": "Miksi minun pitäisi käyttää ABP.IO-alustaa sen sijaan, että luon uuden ratkaisun tyhjästä?",
"WhyUseAbpIoPlatformFaqExplanation": "Katso <a href=\"https://docs.abp.io/en/commercial/latest/why-abp-io-platform \"> kyseisestä asiakirjasta </a> yksityiskohtainen selitys siitä, miksi ABP.IO Platformin käyttäminen on huomattavasti edullisempaa kuin kaiken tekeminen itse."
"WhyUseAbpIoPlatformFaqExplanation": "Katso <a href=\"https://docs.abp.io/en/commercial/latest/why-abp-io-platform \"> kyseisestä asiakirjasta </a> yksityiskohtainen selitys siitä, miksi ABP.IO Platformin käyttäminen on huomattavasti edullisempaa kuin kaiken tekeminen itse.",
"MultipleOrganizationInfo": "Katso kaikki organisaatiosi"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json

@ -405,6 +405,7 @@
"WhatHappensWhenLicenseEndsExplanation6": "Vous ne pouvez plus bénéficier du <a href=\"{0}\">support premium</a>.",
"WhatHappensWhenLicenseEndsExplanation7": "Vous pouvez prolonger (renouveler) votre licence si vous souhaitez continuer à bénéficier de ces avantages. Si vous prolongez votre licence dans <strong>{3} jours</strong> après l'expiration de votre licence, les remises suivantes seront appliquées : Licence d'équipe {0} ; Licence commerciale {1} ; Licence Entreprise {2}.",
"BlazoriseLicense": "Faut-il acheter une licence Blazorise ?",
"BlazoriseLicenseExplanation": "Nous avons conclu un accord entre Volosoft et Megabit, dans le cadre duquel la licence Blazorise est intégrée aux produits ABP Commercial, de sorte que nos clients n'ont pas besoin d'acheter une licence Blazorise supplémentaire."
"BlazoriseLicenseExplanation": "Nous avons conclu un accord entre Volosoft et Megabit, dans le cadre duquel la licence Blazorise est intégrée aux produits ABP Commercial, de sorte que nos clients n'ont pas besoin d'acheter une licence Blazorise supplémentaire.",
"MultipleOrganizationInfo": "Voir toutes vos organisations"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json

@ -404,6 +404,7 @@
"WhatHappensWhenLicenseEndsExplanation6": "अब आप <a href=\"{0}\">प्रीमियम समर्थन</a> प्राप्त नहीं कर सकते।",
"WhatHappensWhenLicenseEndsExplanation7": "यदि आप इन लाभों को प्राप्त करना जारी रखना चाहते हैं तो आप अपने लाइसेंस का विस्तार (नवीनीकरण) कर सकते हैं। यदि आप अपना लाइसेंस समाप्त होने के बाद <strong>{3} दिन</strong> के भीतर अपना लाइसेंस बढ़ाते हैं, तो निम्नलिखित छूट लागू होंगी: टीम लाइसेंस {0}; व्यवसाय लाइसेंस {1}; उद्यम लाइसेंस {2}।",
"BlazoriseLicense": "क्या हमें ब्लेज़ोराइज़ लाइसेंस खरीदने की ज़रूरत है?",
"BlazoriseLicenseExplanation": "हमारे पास Volosoft और Megabit के बीच एक समझौता है, इस समझौते के साथ Blazorise लाइसेंस को ABP वाणिज्यिक उत्पादों के साथ बंडल किया गया है, इसलिए हमारे ग्राहकों को एक अतिरिक्त Blazorise लाइसेंस खरीदने की आवश्यकता नहीं है।"
"BlazoriseLicenseExplanation": "हमारे पास Volosoft और Megabit के बीच एक समझौता है, इस समझौते के साथ Blazorise लाइसेंस को ABP वाणिज्यिक उत्पादों के साथ बंडल किया गया है, इसलिए हमारे ग्राहकों को एक अतिरिक्त Blazorise लाइसेंस खरीदने की आवश्यकता नहीं है।",
"MultipleOrganizationInfo": "अपने सभी संगठन देखें"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json

@ -601,7 +601,7 @@
"Purchase_TrainingPrice": "Képzési ár",
"Purchase_OnboardingTraining": "ABP Onboarding és webalkalmazás-fejlesztés élő képzés",
"TotalDeveloperPrice": "Teljes fejlesztői ár",
"Purchase_PricePerDeveloper": "<span>{0} {1}</span> fejlesztőnként",
"Purchase_PricePerDeveloper": "<span>{0}</span> fejlesztőnként",
"Purchase_IncludedDeveloperInfo": "{0} {1} tartalmazza.",
"Purchase_LicenseExtraDeveloperPurchaseMessage": "A(z) <span class=\"fw-6\">{0} licensz</span> {1} fejlesztőt tartalmaz. Hozzáadhat további fejlesztőket most vagy később.",
"StartupTemplates_Page_Title": "Az indítási sablonok",
@ -753,6 +753,7 @@
"ExtendPaymentInfoSection_DeveloperPrice": "{0}x További Fejlesztő(k)",
"ExtendPaymentInfoSection_DiscountRate": "Kedvezmény: {0}%",
"TotalNetPrice": "Total Net Price",
"BlackFridayDiscount": "Black Friday Kedvezmény"
"BlackFridayDiscount": "Black Friday Kedvezmény",
"MultipleOrganizationInfo": "Tekintse meg az összes szervezetét"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json

@ -383,6 +383,7 @@
"TryForFree": "Prófaðu ókeypis",
"TrialLicenseExpiredInfo": "Prófunartímabil þitt er útrunnið!",
"CommercialNewsletterConfirmationMessage": "Ég samþykki <a href=\"https://commercial.abp.io/TermsConditions\">skilmálana</a> og <a href=\"https://commercial.abp.io/Privacy\">persónuverndarstefnuna </a>.",
"BlackFridayDiscount": "Black Friday afsláttur"
"BlackFridayDiscount": "Black Friday afsláttur",
"MultipleOrganizationInfo": "Sjá öll samtök þín"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json

@ -404,6 +404,7 @@
"WhatHappensWhenLicenseEndsExplanation6": "Non è più possibile ottenere il <a href=\"{0}\">supporto premium</a>.",
"WhatHappensWhenLicenseEndsExplanation7": "Puoi estendere (rinnovare) la tua licenza se desideri continuare a ottenere questi vantaggi. Se estendi la licenza entro <strong>{3} giorni</strong> dalla scadenza della licenza, verranno applicati i seguenti sconti: Licenza Team {0}; Licenza commerciale {1}; Licenza aziendale {2}.",
"BlazoriseLicense": "Dobbiamo acquistare la licenza di Blazorise?",
"BlazoriseLicenseExplanation": "Abbiamo un accordo tra Volosoft e Megabit, con il quale la licenza di Blazorise viene fornita in bundle con i prodotti commerciali ABP, pertanto i nostri clienti non hanno bisogno di acquistare una licenza Blazorise aggiuntiva."
"BlazoriseLicenseExplanation": "Abbiamo un accordo tra Volosoft e Megabit, con il quale la licenza di Blazorise viene fornita in bundle con i prodotti commerciali ABP, pertanto i nostri clienti non hanno bisogno di acquistare una licenza Blazorise aggiuntiva.",
"MultipleOrganizationInfo": "Visualizza tutte le tue organizzazioni"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json

@ -383,6 +383,7 @@
"TryForFree": "Probeer gratis",
"TrialLicenseExpiredInfo": "Uw proeflicentieperiode is verlopen!",
"CommercialNewsletterConfirmationMessage": "Ik ga akkoord met de <a href=\"https://commercial.abp.io/TermsConditions\">Algemene voorwaarden</a> en het <a href=\"https://commercial.abp.io/Privacy\">Privacybeleid </a>.",
"BlackFridayDiscount": "Black Friday korting"
"BlackFridayDiscount": "Black Friday korting",
"MultipleOrganizationInfo": "Bekijk al uw organisaties"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json

@ -383,6 +383,7 @@
"TryForFree": "Wypróbuj za darmo",
"TrialLicenseExpiredInfo": "Twoja licencja próbna wygasła!",
"CommercialNewsletterConfirmationMessage": "Wyrażam zgodę na <a href=\"https://commercial.abp.io/TermsConditions\">Warunki</a> i <a href=\"https://commercial.abp.io/Privacy\">Politykę prywatności </a>.",
"BlackFridayDiscount": "Zniżka Black Friday"
"BlackFridayDiscount": "Zniżka Black Friday",
"MultipleOrganizationInfo": "Zobacz wszystkie swoje organizacje"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json

@ -406,6 +406,7 @@
"WhatHappensWhenLicenseEndsExplanation4": "Você não pode instalar novos módulos e temas adicionados à plataforma comercial da ABP após o término de sua licença.",
"WhatHappensWhenLicenseEndsExplanation5": "Você não pode usar o ABP Suite",
"WhatHappensWhenLicenseEndsExplanation6": "Você não pode mais obter o <a href==\"{0}\">apoio de premium</a>.",
"WhatHappensWhenLicenseEndsExplanation7": "Você pode estender (renovar) sua licença se quiser continuar obtendo esses benefícios. Se você estender sua licença dentro de <strong>{3} dias</strong> após a expiração de sua licença, os seguintes descontos serão aplicados: Licença de equipe {0}; Licença Comercial {1}; Licença empresarial {2}."
"WhatHappensWhenLicenseEndsExplanation7": "Você pode estender (renovar) sua licença se quiser continuar obtendo esses benefícios. Se você estender sua licença dentro de <strong>{3} dias</strong> após a expiração de sua licença, os seguintes descontos serão aplicados: Licença de equipe {0}; Licença Comercial {1}; Licença empresarial {2}.",
"MultipleOrganizationInfo": "Veja todas as suas organizações"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json

@ -383,6 +383,7 @@
"TryForFree": "Încearcă pe gratis",
"TrialLicenseExpiredInfo": "Perioada de licență de probă a expirat!",
"CommercialNewsletterConfirmationMessage": "Sunt de acord cu <a href=\"https://commercial.abp.io/TermsConditions\">Termenii și condițiile</a> și cu <a href=\"https://commercial.abp.io/Privacy\">Politica de confidențialitate </a>.",
"BlackFridayDiscount": "Black Friday Discount"
"BlackFridayDiscount": "Black Friday Discount",
"MultipleOrganizationInfo": "Vedeți toate organizațiile dvs"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json

@ -383,6 +383,7 @@
"TryForFree": "Попробуй бесплатно",
"TrialLicenseExpiredInfo": "Срок действия вашей пробной лицензии истек!",
"CommercialNewsletterConfirmationMessage": "Я согласен с <a href=\"https://commercial.abp.io/TermsConditions\"> Положениями и условиями </a> и <a href=\"https://commercial.abp.io/Privacy\"> Политикой конфиденциальности </a>.",
"BlackFridayDiscount": "Черная пятница Скидка"
"BlackFridayDiscount": "Черная пятница Скидка",
"MultipleOrganizationInfo": "Просмотреть все ваши организации"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json

@ -402,6 +402,7 @@
"WhatHappensWhenLicenseEndsExplanation6": "Už nemôžete získať <a href=\"{0}\">prémiovú podporu</a>.",
"WhatHappensWhenLicenseEndsExplanation7": "Ak chcete naďalej využívať tieto výhody, môžete si licenciu predĺžiť (obnoviť). Ak predĺžite svoju licenciu do <strong>30 dní</strong> po vypršaní platnosti licencie, budú sa uplatňovať nasledujúce zľavy: Tímová licencia {0}; Obchodná licencia {1}; Podniková licencia {2}",
"BlazoriseLicense": "Musíme si kúpiť licenciu Blazorise?",
"BlazoriseLicenseExplanation": "Máme dohodu medzi spoločnosťami Volosoft a Megabit, na základe ktorej je licencia Blazorise pribalená k produktom ABP Commercial, preto si naši zákazníci nemusia kupovať ďalšiu licenciu Blazorise."
"BlazoriseLicenseExplanation": "Máme dohodu medzi spoločnosťami Volosoft a Megabit, na základe ktorej je licencia Blazorise pribalená k produktom ABP Commercial, preto si naši zákazníci nemusia kupovať ďalšiu licenciu Blazorise.",
"MultipleOrganizationInfo": "Pozrite si všetky vaše organizácie"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json

@ -383,6 +383,7 @@
"TryForFree": "Poskusite brezplačno",
"TrialLicenseExpiredInfo": "Vaša preizkusna licenca je potekla!",
"CommercialNewsletterConfirmationMessage": "Strinjam se s <a href=\"https://commercial.abp.io/TermsConditions\">pogoji in določili</a> in <a href=\"https://commercial.abp.io/Privacy\">pravilnikom o zasebnosti </a>.",
"BlackFridayDiscount": "Popust Black Friday"
"BlackFridayDiscount": "Popust Black Friday",
"MultipleOrganizationInfo": "Oglejte si vse svoje organizacije"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json

@ -610,7 +610,7 @@
"Purchase_TrainingPrice": "Eğitim Fiyatı",
"Purchase_OnboardingTraining": "ABP Onboarding & Web Uygulama Geliştirme Canlı Eğitimi",
"TotalDeveloperPrice": "Toplam Geliştirici Fiyatı",
"Purchase_PricePerDeveloper": "<span>{0} {1}</span> geliştirici başına",
"Purchase_PricePerDeveloper": "<span>{0}</span> geliştirici başına",
"Purchase_IncludedDeveloperInfo": "{0} {1} dahil.",
"Purchase_LicenseExtraDeveloperPurchaseMessage": "<span class=\"fw-6\">{0} lisansı</span> {1} geliştirici(ler) içerir. Şimdi veya daha sonra ek geliştiriciler ekleyebilirsiniz.",
"StartupTemplates_Page_Title": "ABP Başlangıç Şablonları",
@ -841,6 +841,7 @@
"OneCodeBaseMultipleDevices": "Tek Kod Tabanı, Birden Çok Cihaz",
"OneCodeBaseMultipleDevices_Description": "ABP Mobil uygulamaları çapraz platformdur. iOS ve Android cihazlara yüklenmeye ve çalıştırılmaya hazırdırlar ve tek bir kod tabanı kullanarak farklı form faktörlerine uyum sağlarlar. Geliştiricilerin kullanıcı arayüzünü ve ön uç kodunu yalnızca bir kez oluşturması gerekir, desteklemek istediğiniz her cihaz için kodu uyarlamanıza gerek yoktur.",
"ComesWithTheSourceCode": "Kaynak Koduyla Birlikte Geliyor",
"ComesWithTheSourceCode_Description": "Mobil uygulamalar kaynak koduyla birlikte sağlanır. Marka yönergelerini karşılamak için uygulamalarınızın UX/UI'sini kolayca özelleştirin."
"ComesWithTheSourceCode_Description": "Mobil uygulamalar kaynak koduyla birlikte sağlanır. Marka yönergelerini karşılamak için uygulamalarınızın UX/UI'sini kolayca özelleştirin.",
"MultipleOrganizationInfo": "Tüm Organizasyonlarınızı Görün"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json

@ -383,6 +383,7 @@
"TryForFree": "Thử miễn phí",
"TrialLicenseExpiredInfo": "Thời gian cấp phép dùng thử của bạn đã hết hạn!",
"CommercialNewsletterConfirmationMessage": "Tôi đồng ý với <a href=\"https://commercial.abp.io/TermsConditions\"> Điều khoản & điều kiện </a> và <a href=\"https://commercial.abp.io/Privacy\"> Chính sách quyền riêng tư </a>.",
"BlackFridayDiscount": "Giảm giá Black Friday"
"BlackFridayDiscount": "Giảm giá Black Friday",
"MultipleOrganizationInfo": "Xem tất cả các tổ chức của bạn"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json

@ -600,7 +600,7 @@
"Purchase_TrainingPrice": "培训价格",
"Purchase_OnboardingTraining": "ABP 熟悉使用和 Web 应用程序开发现场培训",
"TotalDeveloperPrice": "开发商总价",
"Purchase_PricePerDeveloper": "<span>{0} {1}</span> 每个开发者",
"Purchase_PricePerDeveloper": "<span>{0}</span> 每个开发者",
"Purchase_IncludedDeveloperInfo": "{0} {1} 包括在内。",
"Purchase_LicenseExtraDeveloperPurchaseMessage": "<span class=\"fw-6\">{0} 许可</span> 包含 {1} 个开发者。 您可以现在或以后添加其他开发人员。",
"StartupTemplates_Page_Title": "ABP启动模板",
@ -842,6 +842,7 @@
"BlazoriseSupportExplanation4": "如果您有有效的ABP商业版许可证,您还将拥有Blazorise PRO许可证。您可以在<a href=\"https://blazorise.com/support/user/manage/license\" rel=\"nofollow\">blazorise.com/support/user/manage/license</a>获取您的Blazorise许可密钥。",
"BlazoriseSupportExplanation5": "您可以在support网站上发布您的问题,并为您的应用程序生成一个产品令牌。",
"ExtraQuestionCreditsFaqTitle": "我可以购买额外的问题支持次数吗?",
"ExtraQuestionCreditsFaqExplanation": "是的,您可以购买额外的问题支持次数,请发送电子邮件至<a href=\"mailto:info@abp.io\">info@abp.io</a>,并提供您的组织名称。以下是额外问题支持次数的价格列表: <ul><li>50次问题 $999</li><li>25次问题 $625</li><li>15次问题 $450</li></ul>"
"ExtraQuestionCreditsFaqExplanation": "是的,您可以购买额外的问题支持次数,请发送电子邮件至<a href=\"mailto:info@abp.io\">info@abp.io</a>,并提供您的组织名称。以下是额外问题支持次数的价格列表: <ul><li>50次问题 $999</li><li>25次问题 $625</li><li>15次问题 $450</li></ul>",
"MultipleOrganizationInfo": "查看您的所有组织"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json

@ -408,6 +408,7 @@
"WhatHappensWhenLicenseEndsExplanation6": "您無法再獲得<a href=\"{0}\">高級支持</a>。",
"WhatHappensWhenLicenseEndsExplanation7": "如果您想繼續獲得這些好處,您可以延長(更新)您的許可證。如果您在許可到期後 <strong>{3} 天</strong> 內延長許可,將應用以下折扣:團隊許可 {0};營業執照{1};企業許可證{2}。",
"DoesTheSubscriptionRenewAutomatically": "許可會自動續費嗎?",
"DoesTheSubscriptionRenewAutomaticallyExplanation": "ABP 商業版沒有自動續費的計費模式。因此,在您的許可期結束時,<strong>您的訂閱將不會自動續訂</strong>。如果您希望繼續享受ABP商業版的服務,請在<a href=\"/my-organizations\">組織管理頁面</a>手動進行續費操作。如果您擁有多個組織,您可以點擊即將到期的組織上的\"管理\"按鈕,然後點擊\"立即續費\"按鈕來續訂您的許可。您還可以查看<a href=\"/faq#what-happens-when-license-ends\">許可到期後會發生什麼?</a>部分了解更多信息。"
"DoesTheSubscriptionRenewAutomaticallyExplanation": "ABP 商業版沒有自動續費的計費模式。因此,在您的許可期結束時,<strong>您的訂閱將不會自動續訂</strong>。如果您希望繼續享受ABP商業版的服務,請在<a href=\"/my-organizations\">組織管理頁面</a>手動進行續費操作。如果您擁有多個組織,您可以點擊即將到期的組織上的\"管理\"按鈕,然後點擊\"立即續費\"按鈕來續訂您的許可。您還可以查看<a href=\"/faq#what-happens-when-license-ends\">許可到期後會發生什麼?</a>部分了解更多信息。",
"MultipleOrganizationInfo": "查看您的所有組織"
}
}

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json

@ -438,7 +438,7 @@
"CoolestCompaniesUseABPFramework": "Coolest Companies Use <span class=\"fw-bold\">ABP Framework</span>",
"Index_Page_Testimonial_1": "ABP Framework is not just a tool but a catalyst that has accelerated my growth as a developer. It has made it possible for me to build new features faster than ever before, reminiscent of the experiences of other users. The unified coding pattern has streamlined my projects, giving me more time to focus on creating rather than troubleshooting.\nI would say the ABP Framework has been the cornerstone of my early professional journey. It has facilitated my transition from an aspiring developer to a confident professional ready to make a mark in the software world. I am looking forward to the exciting projects that await me, knowing that ABP will be there to guide me. It is more than just a product; it's a partner in success.",
"Index_Page_Testimonial_2": "ABP Framework is not only a framework, it is also a guidance for project development/management, because it provides DDD, GenericRepository, DI, Microservice, Modularity trainings. Even if you are not going to use framework itself, you can develop yourself with docs.abp.io which is well and professionally prepared. (OpenIddict, Redis, Quartz etc.)\nBecause many thing pre-built, it shortens project development time significantly. (Such as login page, exception handling, data filtering-seeding, audit logging, localization, auto api controller etc.)\nAs an example from our app, i have used Local Event Bus for stock control. So, I am able to manage order movements by writing stock handler.\nIt is wonderful not to lose time for CreationTime, CreatorId. They are filled automatically.",
"VideosLoginAndRegisterMessage": "You must sign in to watch videos. You can create an account for watch if you haven't.",
"VideosLoginAndRegisterMessage": "To be able to watch videos, you must sign in.",
"Filter": "Filter",
"VideoCourses": "Video Courses"
}

35
abp_io/README.md

@ -1,11 +1,32 @@
## Abp.io platform localization
## ABP Platform Websites Localization
This project is all localized resources of the abp.io platform.
This is the localization project of [abp.io platform](https://abp.io).
All *.abp.io websites are built on top of ABP Framework, and it uses ABP Framework's localization system.
You can correct a wrong localization text, or you can translate it into your own language.
By doing so, [abp.io](https://abp.io) websites will be translated into a new language and it will help to expand the ABP Community.
If you like, you can contribute to the localization resources in this project.
For example: `AbpIoLocalization\AbpIoLocalization\Www\Localization\Resources\zh-Hans.json`
If the file is missing some translations or the translation is wrong, you can add it.
If the language file is missing (eg `kr.json`), you can also add it.
Please refer to the [Contribution Guide](https://github.com/abpframework/abp/blob/dev/docs/en/Contribution/Index.md) for details.
## How to Translate abp.io Into Your Language:
1. Install [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) command line tool.
2. Run the following command to generate the localization file.
For example, for translating from English to French `fr`:
```bash
abp translate -c fr
```
3. After you fill in the empty localization keys, run the following command to apply it.
```bash
abp translate -a
```
4. Send your PR to the team; after the review process, we wil merge it.
---
## References:
* [ABP CLI Translate Command](https://docs.abp.io/en/abp/latest/Contribution/Index#using-the-abp-translate-command)
* [Contribution Guide](https://github.com/abpframework/abp/blob/dev/docs/en/Contribution/Index.md)

2
common.props

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>8.0.0-rc.3</Version>
<Version>8.1.0</Version>
<NoWarn>$(NoWarn);CS1591;CS0436</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io/</PackageProjectUrl>

223
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/POST.md

@ -0,0 +1,223 @@
# ABP.IO Platform 8.0 RC Has Been Released
Today, we are happy to release the [ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) version **8.0 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version.
Try this version and provide feedback for a more stable version of ABP v8.0! Thanks to all of you.
## Get Started with the 8.0 RC
Follow the steps below to try version 8.0.0 RC today:
1) **Upgrade** the ABP CLI to version `8.0.0-rc.1` using a command line terminal:
````bash
dotnet tool update Volo.Abp.Cli -g --version 8.0.0-rc.1
````
**or install** it if you haven't before:
````bash
dotnet tool install Volo.Abp.Cli -g --version 8.0.0-rc.1
````
2) Create a **new application** with the `--preview` option:
````bash
abp new BookStore --preview
````
See the [ABP CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all the available options.
> You can also use the [Get Started](https://abp.io/get-started) page to generate a CLI command to create a new application.
You can use any IDE that supports .NET 8.x, like [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/).
## Migration Guides
There are a few breaking changes in this version that may affect your application.
Please see the following migration documents, if you are upgrading from v7.x or earlier:
* [ABP Framework 7.x to 8.0 Migration Guide](https://docs.abp.io/en/abp/8.0/Migration-Guides/Abp-8_0)
* [ABP Commercial 7.x to 8.0 Migration Guide](https://docs.abp.io/en/commercial/8.0/migration-guides/v8_0)
## What's New with ABP Framework 8.0?
In this section, I will introduce some major features released in this version.
Here is a brief list of titles explained in the next sections:
* Upgraded to .NET 8.0
* Upgraded to Angular 17
* Dynamic Claims
* CDN Support for Bundling & Minification System
* Read-Only Repositories
* Account Module: Set Username After Social/External Login
* Other News...
### Upgraded to .NET 8.0
We've upgraded the ABP Framework to .NET 8.0, so you need to move your solutions to .NET 8.0 if you want to use ABP 8.0. You can check [Microsoft’s Migrate from ASP.NET Core 7.0 to 8.0 documentation](https://learn.microsoft.com/en-us/aspnet/core/migration/70-80), to see how to update an existing ASP.NET Core 7.0 project to ASP.NET Core 8.0.
### Upgraded to Angular 17
Angular 17 [was released on November 8](https://blog.angular.io/introducing-angular-v17-4d7033312e4b) and ABP Framework & ABP Commercial startup templates were immediately migrated to **Angular 17**!
So, when you create a new solution with the Angular UI, you will take advantage of the new Angular with the new cutting-edge features and enhancements right from the start!
### Dynamic Claims
The **Dynamic Claims** feature is used to dynamically generate claims for the user in each request. It's used to automatically and dynamically override the configured claim values in the client's authentication token/cookie by the latest user claims.
In the prior versions, whenever a user changed their email address or confirmed their own email address, or any other information related to the user (and if it's in the claims), he/she would need to logout and then login to refresh its claims. The new **Dynamic Claims** feature overcomes this problem and allows to **always get the latest user claims**.
This feature is disabled by default and you can enable it easily for your existing MVC applications by following the [Dynamic Claims documentation](https://docs.abp.io/en/abp/8.0/Dynamic-Claims). For the other UI options (Angular & Blazor UIs), you don't need to enable this feature, since they obtain claims ftom a configuration endpoint.
> **Note**: Beginning from the v8.0, all the startup templates are pre-configured and the **Dynamic Claims** feature is enabled by default.
### CDN Support for Bundling & Minification System
In this version, ABP Framework's [Bundling & Minification System](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Bundling-Minification) provides CDN support for MVC / Razor Pages UI. The bundling system automatically recognizes the external/CDN files and places them as link/script tags on the page along with the bundled CSS/JSS files.
> Read the documentation for more info: https://docs.abp.io/en/abp/8.0/UI/AspNetCore/Bundling-Minification
### Read-Only Repositories
ABP Framework provides read-only repository interfaces (`IReadOnlyRepository<>` or `IReadOnlyBasicRepository<>`) to explicitly indicate that your purpose is to query data, but not change it. It uses [EF Core's No-Tracking Feature](https://learn.microsoft.com/en-us/ef/core/querying/tracking#no-tracking-queries) behind the scenes, which means the entities returned from the repository will not be tracked by the EF Core's [change tracker](https://learn.microsoft.com/en-us/ef/core/change-tracking/) and thanks to that you get significant performance gains.
```csharp
public class MyService
{
private readonly IReadOnlyRepository<Book, Guid> _bookRepository;
public async Task MyMethod()
{
var books = await _bookRepository.GetListAsync(); //change tracking not involved
//...
}
}
```
> In addition to the read-only repository interfaces, ABP Framework introduces the `IRepository.DisableTracking()` and `IRepository.EnableTracking()` extension methods to allow developers to disable/enable entity tracking by these methods manually. If you don't want to use the read-only repositories, you can use these methods to enable or disable the change tracker controlled. Read the documentation to learn more: [https://docs.abp.io/en/abp/8.0/Repositories#enabling-disabling-the-change-tracking](https://docs.abp.io/en/abp/8.0/Repositories#enabling-disabling-the-change-tracking)
### Account Module: Set Username After Social/External Login
Prior to this version, when you registered with your social accounts for the first time, your email address was becoming your username and it was shown everywhere in the application. Therefore, you would need to update your username later on and this is not a good user experience.
Thus, in this version, we have enhanced this flow, and now, when you register as an external user for the first time, a username and email address are shown you in a form for you to revise and update if you want, before logging into the application. Thanks to that, after the social registration you would not need to update your username and email address. This is also good at the point of GDPR regulations because your email address will not be shown as a username and will not exposed.
![](account-module-register.png)
### Other News
* LDAP over SSL (LDAPS) setting has been added and recommended to establish a secure connection. See [#17865](https://github.com/abpframework/abp/pull/17865) for more information.
* Object Mapping Enhancements (supports mapping collection of objects for custom object mappers).
* Email Sending Improvements (sending attachments with `IEmailSender.QueueAsync()` method).
## What's New with ABP Commercial 8.0?
We've also worked on ABP Commercial to align the features and changes made in the ABP Framework. The following sections introduce a few new features coming with ABP Commercial 8.0.
### Suite: Generating Master/Detail Relationship
In this version, we have introduced the **Master/Detail Relationship** support in Suite. The Master-Detail (or Master-Child) relationship refers to a hierarchical connection between two entities, where one entity (the master or parent entity) influences or controls the behavior or properties of another element (the child entity) relationship. The relationship between **Order - Order Lines** can be considered as an example of a master-detail relationship.
![](suite-master-child-datagrid.png)
ABP Suite allows you to create a master-detail relationship with a few clicks. It generates the necessary code for the master and detail tables, including the foreign key relationship between the two tables.
To establish a master-detail relationship, you need to apply the following two steps:
1-) Create the master entity,
2-) Create a child entity and associate it with a master entity.
That's it! ABP Suite will be generating the entities, making the related configurations, establishing database relations (including the foreign key relationship), generating the UI for the master entity (with child-grids for child entities), and so on...
It’s already documented and you can read the documentation at [https://docs.abp.io/en/commercial/8.0/abp-suite/creating-master-detail-relationship](https://docs.abp.io/en/commercial/8.0/abp-suite/creating-master-detail-relationship).
#### Known Issues
* After you generate CRUD pages via Suite for the Angular UI, you should start the backend project and run the `abp generate-proxy -t ng` command in the root directory of the Angular application manually. It will be automatically done with the next version, so you will not need to run the command manually in further versions.
### Get Profile Picture From Social/External Logins
A user's profile picture would be blank when they first register for an application using a social account through an external authentication provider like Google or Facebook because it hasn't been configured yet. The user must update their profile photo after logging into the application.
In order to save the user from having to change their profile picture after logging in for the first time, we have improved this behavior in this version and are now attempting to retrieve the user's profile picture from external authentication providers (like Google) and set it as their profile picture. Later on, if desired, he or she might modify the profile image.
### Switch Ocelot to YARP for the API Gateway
Until this version, ABP Commercial was using the [Ocelot](https://github.com/ThreeMammals/Ocelot) for the API Gateway, in the [Microservice Startup Template](https://docs.abp.io/en/commercial/latest/startup-templates/microservice/index). Since the **Ocelot** library is not actively maintained, we have searched for an alternative and decided to switch from Ocelot to [YARP](https://github.com/microsoft/reverse-proxy) for the API Gateway. YARP is maintained by Microsoft and is actively being developed and seems a better alternative than Ocelot and provides the same feature stack and even more.
You can read the [Migrating to YARP](https://docs.abp.io/en/commercial/8.0/migration-guides/migrating-to-yarp) documentation for migrating your existing microservice application's API Gateway from [Ocelot](https://github.com/ThreeMammals/Ocelot) to [YARP](https://github.com/microsoft/reverse-proxy).
> We have made the all related changes in the Microservice Startup Template, and also updated the documentation, which you can read [here](https://docs.abp.io/en/commercial/8.0/startup-templates/microservice/gateways).
### Password Complexity Indicators (MVC & Blazor UIs)
In v7.4, we have introduced the [Password Complexity Indicators for Angular UI](https://docs.abp.io/en/commercial/7.4/ui/angular/password-complexity-indicator-component) and with this version, we have implemented it for the MVC & Blazor UIs as well. You can use this feature to dynamically evaluate and rate the strength of user-generated passwords, providing real-time feedback to users as they create or update their passwords.
![](password-complexity-indicators.png)
### Read-Only View for Users Page
In your application, you may want to grant permission to a specific group or people to read-only view the users of your application to be able to do some actions. For example, you may want to marketing team to see the users to organize campaigns for the customers, or make controls. In this case, you can grant default permissions for these groups, however, they could not see the details of a user, because in the current design, if the edit permission is not granted you can't see the detailed info for a user.
![](identity-users.gif)
In this version, we have added the read-only view action to the user's page. This allows you to only grant the default view permission to the specific users and allow them to view user information as read-only and not allow them to change or modify it.
### Export & Import Users as Excel / CSV
With v8.0, now it's possible to import and export user records in Excel and CSV formats. You can import external users, or import users from Excel or CSV files and also you can export users to Excel or CSV files:
![](users-page.png)
## Community News
### Highlights from .NET 8.0
Our team has closely followed the ASP.NET Core and Entity Framework Core 8.0 releases, read Microsoft's guides and documentation, and adapted the changes to our ABP.IO Platform. We are proud to say that we've shipped the ABP 8.0 RC.1 based on .NET 8.0 just after Microsoft's .NET 8.0 release.
In addition to the ABP's .NET 8.0 upgrade, our team has created 13 great articles to highlight the important features coming with ASP.NET Core 8.0 and Entity Framework Core 8.0.
> You can read [this post](https://volosoft.com/blog/Highlights-for-ASP-NET-Entity-Framework-Core-NET-8-0) to see the list of all articles.
### New ABP Community Articles
In addition to [the 13 articles to highlight .NET 8.0 features written by our team](https://volosoft.com/blog/Highlights-for-ASP-NET-Entity-Framework-Core-NET-8-0), here are some of the recent posts added to the [ABP Community](https://community.abp.io/):
* [Upgrade Your Existing Projects to .NET 8 & ABP 8.0](https://community.abp.io/posts/upgrade-your-existing-projects-to-.net-8-abp-8.0-x0n7hiqr) by [Engincan Veske](https://github.com/EngincanV)
* [How to Upload and Download Files in the ABP Framework using Angular](https://community.abp.io/posts/how-to-upload-and-download-files-in-the-abp-framework-using-angular-que8cdr8) by [Mahmut Gündoğdu](https://github.com/mahmut-gundogdu)
* New **ABP Framework Essentials** Videos by [Hamza Albreem](https://github.com/braim23):
* [ABP Essentials - Interception](https://community.abp.io/videos/abp-essentials-interception-ath78xhw)
* [ABP Essentials - Virtual File System](https://community.abp.io/videos/abp-essentials-virtual-file-system-hpgr2j72)
* [ABP Framework Essentials - Localization](https://community.abp.io/videos/abp-framework-essentials-localization-7taieh68)
* [ABP Framework Essentials - Dependency Injection](https://community.abp.io/videos/abp-framework-essentials-dependency-injection-q241mfrf)
* See the playlist for other videos of this series: https://www.youtube.com/playlist?list=PLsNclT2aHJcNupH2wz83y7htugpLoUZ_B
Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://community.abp.io/articles/submit) to the ABP Community.
### We were in the .NET Conf 2023
Microsoft has released .NET 8.0 and celebrated it with a 3-day international online conference. The core team members of ABP Framework, [Alper Ebiçoğlu](https://twitter.com/alperebicoglu) and [Enis Necipoğlu](https://twitter.com/EnisNecipoglu) gave speeches at the .NET Conf 2023.
[Alper Ebiçoğlu](https://twitter.com/alperebicoglu)'s topic was "Building Multi-Tenant ASP.NET Core Applications and ABP Framework" and in this talk, he talked about what's SaaS development, what are its pros and challenges and multi-tenant development with the open-source ABP Framework:
<iframe width="560" height="315" src="https://www.youtube.com/embed/3uWeyEbV4c4?si=XuU8-QJs2w5j6Inp" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
On the other hand, [Enis Necipoğlu](https://twitter.com/EnisNecipoglu)'s topic was "Reactive programming with .NET MAUI" and he talked about applying reactive programming in .NET MAUI with MVVM and ReactiveUI:
<iframe width="560" height="315" src="https://www.youtube.com/embed/i0EFuRF2u-w?si=wPTSDxtbfkzMF5CN" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
### ABP Community Talks 2023.8: What’s coming with .NET 8.0 & ABP v8.0
![](community-talk-2023-8.png)
In this episode of ABP Community Talks, 2023.8; [Steve Sanderson](https://twitter.com/stevensanderson) will be our guest speaker and we'll talk about .NET 8.0 and ABP 8.0 with the ABP Core Team. We will dive into the features that came with .NET 8.0, how they are implemented in ABP 8.0, and the highlights in the .NET Conf 2023 with [Halil İbrahim Kalkan](https://github.com/hikalkan), [Alper Ebicoglu](https://github.com/ebicoglu), [Engincan Veske](https://github.com/EngincanV), [Berkan Sasmaz](https://github.com/berkansasmaz) and [Bige Besikci Yaman](https://github.com/bigebesikci).
## Conclusion
This version comes with some new features and a lot of enhancements to the existing features. You can see the [Road Map](https://docs.abp.io/en/abp/8.0/Road-Map) documentation to learn about the release schedule and planned features for the next releases. Please try ABP v8.0 RC and provide feedback to help us release a more stable version.
Thanks for being a part of this community!

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/account-module-register.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/community-talk-2023-8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/identity-users.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/password-complexity-indicators.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/suite-master-child-datagrid.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/users-page.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

2
docs/en/Community-Articles/2023-10-28-EF-Core-8-Primitive-Collections/POST.md

@ -102,7 +102,7 @@ The SQL statement looks like this, and as you can see, it automatically serializ
Executed DbCommand (0ms) [Parameters=
[@p0='Maserati' (Nullable = false) (Size = 8),
@p1='[0,3]' (Nullable = false) (Size = 5),
@p2='Flow' (Nullable = false) (Size = 4)
@p2='GranTurismo' (Nullable = false) (Size = 4)
], CommandType='Text', CommandTimeout='30']
INSERT INTO "Cars" ("Brand", "Colors", "Model")
VALUES (@p0, @p1, @p2)

1
docs/en/Community-Articles/2023-11-06-Blazor-Fullstack-Web-Ui/Post.md

@ -91,4 +91,5 @@ I summarized the new generation Blazor in a very simple way. This architecture w
* You can check Dan Roth's GitHub issue 👉 [github.com/dotnet/aspnetcore/issues/46636](https://github.com/dotnet/aspnetcore/issues/46636).
* Steven Sanderson's YouTube video is very good for understanding these concepts 👉 [Blazor United Prototype Video](https://youtu.be/48G_CEGXZZM).
* "Full Stack Web UI with Blazor" — .NET Conf 2023 video 👉 [learn.microsoft.com/en-us/shows/dotnetconf-2023/full-stack-web-ui-with-blazor-in-dotnet-8](https://learn.microsoft.com/en-us/shows/dotnetconf-2023/full-stack-web-ui-with-blazor-in-dotnet-8)

0
docs/en/Community-Articles/2023-11-97-AOT-Compilation/Post.md → docs/en/Community-Articles/2023-11-17-AOT-Compilation/Post.md

10
docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md

@ -152,4 +152,14 @@ Configure<AbpRabbitMqEventBusOptions>(options =>
});
````
**Example: Configure the queue and exchange optional arguments**
```csharp
Configure<AbpRabbitMqEventBusOptions>(options =>
{
options.ExchangeArguments["x-delayed-type"] = "direct";
options.QueueArguments["x-message-ttl"] = 60000;
});
```
Using these options classes can be combined with the `appsettings.json` way. Configuring an option property in the code overrides the value in the configuration file.

BIN
docs/en/images/book-mastering-abp-framework.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

10
docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md

@ -152,4 +152,14 @@ Configure<AbpRabbitMqEventBusOptions>(options =>
});
````
**示例:配置队列和交换机的额外参数**
```csharp
Configure<AbpRabbitMqEventBusOptions>(options =>
{
options.ExchangeArguments["x-delayed-type"] = "direct";
options.QueueArguments["x-message-ttl"] = 60000;
});
```
使用这些选项类可以与 `appsettings.json` 组合在一起. 在代码中配置选项属性会覆盖配置文件中的值.

9
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
using Microsoft.AspNetCore.Http.Connections;
@ -8,6 +10,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.Components.Server.Extensibility;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.SignalR;
@ -30,7 +33,11 @@ public class AbpAspNetCoreComponentsServerModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
StaticWebAssetsLoader.UseStaticWebAssets(context.Services.GetHostingEnvironment(), context.Services.GetConfiguration());
context.Services.AddHttpClient();
context.Services.AddHttpClient(nameof(BlazorServerLookupApiRequestService))
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.All
});
var serverSideBlazorBuilder = context.Services.AddServerSideBlazor(options =>
{
if (context.Services.GetHostingEnvironment().IsDevelopment())

20
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs

@ -41,27 +41,25 @@ public class BlazorServerLookupApiRequestService : ILookupApiRequestService, ITr
public async Task<string> SendAsync(string url)
{
var client = HttpClientFactory.CreateClient();
var client = HttpClientFactory.CreateClient(nameof(BlazorServerLookupApiRequestService));
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
var uri = new Uri(url, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
{
var baseUrl = string.Empty;
try
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultOrNullAsync("Default");
if (remoteServiceConfig != null)
{
//Blazor tiered -- mode
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Default");
baseUrl = remoteServiceConfig.BaseUrl;
// Blazor tiered mode
var baseUrl = remoteServiceConfig.BaseUrl;
client.BaseAddress = new Uri(baseUrl);
AddHeaders(requestMessage);
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client,
requestMessage, new RemoteServiceConfiguration(baseUrl), string.Empty));
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client, requestMessage, new RemoteServiceConfiguration(baseUrl), string.Empty));
}
catch (AbpException) // Blazor-Server mode.
else
{
baseUrl = NavigationManager.BaseUri;
client.BaseAddress = new Uri(baseUrl);
// Blazor server mode
client.BaseAddress = new Uri(NavigationManager.BaseUri);
foreach (var header in HttpContextAccessor.HttpContext!.Request.Headers)
{
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());

8
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Extensibility/WebAssemblyLookupApiRequestService.cs

@ -32,14 +32,18 @@ public class WebAssemblyLookupApiRequestService : ILookupApiRequestService, ITra
public async Task<string> SendAsync(string url)
{
var client = HttpClientFactory.CreateClient();
var client = HttpClientFactory.CreateClient(nameof(WebAssemblyLookupApiRequestService));
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
AddHeaders(requestMessage);
var uri = new Uri(url, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
{
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Default");
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultOrNullAsync("Default");
if (remoteServiceConfig == null)
{
throw new AbpException("Remote service configuration 'Default' was not found!");
}
client.BaseAddress = new Uri(remoteServiceConfig.BaseUrl);
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client, requestMessage, new RemoteServiceConfiguration(remoteServiceConfig.BaseUrl), string.Empty));
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs

@ -271,7 +271,7 @@ public class AbpInputTagHelperService : AbpTagHelperService<AbpInputTagHelper>
if (string.IsNullOrEmpty(TagHelper.Label))
{
return await GetLabelAsHtmlUsingTagHelperAsync(context, output, isCheckbox) + GetRequiredSymbol(context, output);
return await GetLabelAsHtmlUsingTagHelperAsync(context, output, isCheckbox);
}
var label = new TagBuilder("label");
@ -392,6 +392,8 @@ public class AbpInputTagHelperService : AbpTagHelperService<AbpInputTagHelper>
}
innerOutput.Content.AppendHtml($" <i class=\"{iconClass}\"></i>");
}
innerOutput.Content.AppendHtml(GetRequiredSymbol(context, output));
return innerOutput.Render(_encoder);
}

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs

@ -185,11 +185,12 @@ public class AbpSelectTagHelperService : AbpTagHelperService<AbpSelectTagHelper>
label.AddCssClass("form-label");
label.Attributes.Add("for", GetIdAttributeValue(selectTag));
label.InnerHtml.AppendHtml(_encoder.Encode(TagHelper.Label));
label.InnerHtml.AppendHtml(GetRequiredSymbol(context, output));
return label.ToHtmlString() + GetRequiredSymbol(context, output);
return label.ToHtmlString();
}
return await GetLabelAsHtmlUsingTagHelperAsync(context, output) + GetRequiredSymbol(context, output);
return await GetLabelAsHtmlUsingTagHelperAsync(context, output);
}
protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output)
@ -304,7 +305,11 @@ public class AbpSelectTagHelperService : AbpTagHelperService<AbpSelectTagHelper>
ViewContext = TagHelper.ViewContext,
};
return await labelTagHelper.RenderAsync(new TagHelperAttributeList { { "class", "form-label" } }, context, _encoder, "label", TagMode.StartTagAndEndTag);
var innerOutput = await labelTagHelper.ProcessAndGetOutputAsync(new TagHelperAttributeList { { "class", "form-label" } }, context, "label", TagMode.StartTagAndEndTag);
innerOutput.Content.AppendHtml(GetRequiredSymbol(context, output));
return innerOutput.Render(_encoder);
}
protected virtual async Task<string> GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)

12
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js

@ -32,6 +32,18 @@ var abp = abp || {};
}
var _createDropdownItem = function (record, fieldItem, tableInstance) {
if (fieldItem.divider) {
if (abp.utils.isFunction(fieldItem.divider)) {
return $(fieldItem.divider(record, tableInstance));
}
if (fieldItem.divider === true) {
return $('<li><hr class="dropdown-divider"></li>');
}
return $(fieldItem.divider);
}
var $li = $('<li/>');
var $a = $('<a/>').addClass('dropdown-item');

1
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -79,6 +79,7 @@ public class AspNetCoreApiDescriptionModelProvider : IApiDescriptionModelProvide
}
}
model.NormalizeOrder();
return model;
}

2
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainer.cs

@ -179,7 +179,7 @@ public class BlobContainer : IBlobContainer
{
//TODO: Consider to throw some type of "not found" exception and handle on the HTTP status side
throw new AbpException(
$"Could not found the requested BLOB '{name}' in the container '{ContainerName}'!");
$"Could not find the requested BLOB '{name}' in the container '{ContainerName}'!");
}
return stream;

9
framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs

@ -1,4 +1,5 @@
using Volo.Abp.RabbitMQ;
using System.Collections.Generic;
using Volo.Abp.RabbitMQ;
namespace Volo.Abp.EventBus.RabbitMq;
@ -13,9 +14,13 @@ public class AbpRabbitMqEventBusOptions
public string ExchangeName { get; set; } = default!;
public string? ExchangeType { get; set; }
public ushort? PrefetchCount { get; set; }
public IDictionary<string, object> QueueArguments { get; set; } = new Dictionary<string, object>();
public IDictionary<string, object> ExchangeArguments { get; set; } = new Dictionary<string, object>();
public string GetExchangeTypeOrDefault()
{
return string.IsNullOrEmpty(ExchangeType)

6
framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs

@ -79,14 +79,16 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
new ExchangeDeclareConfiguration(
AbpRabbitMqEventBusOptions.ExchangeName,
type: AbpRabbitMqEventBusOptions.GetExchangeTypeOrDefault(),
durable: true
durable: true,
arguments: AbpRabbitMqEventBusOptions.ExchangeArguments
),
new QueueDeclareConfiguration(
AbpRabbitMqEventBusOptions.ClientName,
durable: true,
exclusive: false,
autoDelete: false,
prefetchCount: AbpRabbitMqEventBusOptions.PrefetchCount
prefetchCount: AbpRabbitMqEventBusOptions.PrefetchCount,
arguments: AbpRabbitMqEventBusOptions.QueueArguments
),
AbpRabbitMqEventBusOptions.ConnectionName
);

2
framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/ExceptionHandling/Localization/en-GB.json

@ -11,7 +11,7 @@
"DefaultErrorMessage403": "You are not authorised!",
"DefaultErrorMessage403Detail": "You are not allowed to perform this operation!",
"DefaultErrorMessage404": "Resource not found!",
"DefaultErrorMessage404Detail": "The resource requested could not found on the server!",
"DefaultErrorMessage404Detail": "The resource requested could not be found on the server!",
"EntityNotFoundErrorMessage": "There is no entity {0} with id = {1}!",
"Error": "Error",
"UnhandledException": "Unhandled exception!",

2
framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/ExceptionHandling/Localization/en.json

@ -11,7 +11,7 @@
"DefaultErrorMessage403": "You are not authorized!",
"DefaultErrorMessage403Detail": "You are not allowed to perform this operation!",
"DefaultErrorMessage404": "Resource not found!",
"DefaultErrorMessage404Detail": "The resource requested could not found on the server!",
"DefaultErrorMessage404Detail": "The resource requested could not be found on the server!",
"EntityNotFoundErrorMessage": "There is no entity {0} with id = {1}!",
"AbpDbConcurrencyErrorMessage": "The data you have submitted has already changed by another user/client. Please discard the changes you've done and try from the beginning.",
"Error": "Error",

2
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs

@ -82,7 +82,7 @@ public class ApiDescriptionFinder : IApiDescriptionFinder, ITransientDependency
}
}
throw new AbpException($"Could not found remote action for method: {method} on the URL: {baseUrl}");
throw new AbpException($"Could not find remote action for method: {method} on the URL: {baseUrl}");
}
public virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(HttpClient client, string baseUrl)

7
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs

@ -22,7 +22,7 @@ public class ApplicationApiDescriptionModel
return new ApplicationApiDescriptionModel
{
Modules = new ConcurrentDictionary<string, ModuleApiDescriptionModel>(), //TODO: Why ConcurrentDictionary?
Types = new Dictionary<string, TypeApiDescriptionModel>()
Types = new SortedDictionary<string, TypeApiDescriptionModel>()
};
}
@ -55,4 +55,9 @@ public class ApplicationApiDescriptionModel
return subModel;
}
public void NormalizeOrder()
{
Modules = Modules.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
}
}

2
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs

@ -35,7 +35,7 @@ public class ModuleApiDescriptionModel
{
RootPath = rootPath,
RemoteServiceName = remoteServiceName,
Controllers = new Dictionary<string, ControllerApiDescriptionModel>()
Controllers = new SortedDictionary<string, ControllerApiDescriptionModel>()
};
}

5
framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs

@ -18,12 +18,13 @@ public class ExchangeDeclareConfiguration
string exchangeName,
string type,
bool durable = false,
bool autoDelete = false)
bool autoDelete = false,
IDictionary<string, object>? arguments = null)
{
ExchangeName = exchangeName;
Type = type;
Durable = durable;
AutoDelete = autoDelete;
Arguments = new Dictionary<string, object>();
Arguments = arguments?? new Dictionary<string, object>();
}
}

5
framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs

@ -23,13 +23,14 @@ public class QueueDeclareConfiguration
bool durable = true,
bool exclusive = false,
bool autoDelete = false,
ushort? prefetchCount = null)
ushort? prefetchCount = null,
IDictionary<string, object>? arguments = null)
{
QueueName = queueName;
Durable = durable;
Exclusive = exclusive;
AutoDelete = autoDelete;
Arguments = new Dictionary<string, object>();
Arguments = arguments?? new Dictionary<string, object>();
PrefetchCount = prefetchCount;
}

2
framework/test/Volo.Abp.BlobStoring.Tests/Volo/Abp/BlobStoring/BlobContainer_Tests.cs

@ -61,7 +61,7 @@ public abstract class BlobContainer_Tests<TStartupModule> : AbpIntegratedTest<TS
using (CurrentTenant.Change(null))
{
// Could not found the requested BLOB...
// Could not find the requested BLOB...
await Assert.ThrowsAsync<AbpException>(async () =>
await Container.GetAllBytesAsync(blobName)
);

4
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json

@ -54,9 +54,9 @@
"Yes": "Yes",
"No": "No",
"Changes": "Changes",
"AverageExecutionDurationInLogsPerDay": "Average execution duration",
"AverageExecutionDurationInLogsPerDay": "Average Execution Duration",
"AverageExecutionDurationInMilliseconds": "Average execution duration in milliseconds",
"ErrorRateInLogs": "Error rate in logs",
"ErrorRateInLogs": "Error Rate in Logs",
"Success": "Success",
"Fault": "Fault",
"NoChanges": "No change(s)",

4
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/tr.json

@ -53,9 +53,9 @@
"Yes": "Evet",
"No": "Hayır",
"UserNameFilter": "Kullanıcı Filtresi",
"AverageExecutionDurationInLogsPerDay": "Ortalama işlem süresi",
"AverageExecutionDurationInLogsPerDay": "Ortalama İşlem Süresi",
"AverageExecutionDurationInMilliseconds": "Milisaniye cinsinden ortalama işlem süresi",
"ErrorRateInLogs": "Loglardaki hata oranı",
"ErrorRateInLogs": "Loglardaki Hata Oranı",
"Success": "Başarılı",
"Fault": "Hatalı",
"NoChanges": "Değişiklik yok",

18
modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaOptions.cs

@ -1,19 +1,17 @@
using System;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using ImageMagick;
namespace Volo.CmsKit.Public.Web.Security.Captcha;
public class CaptchaOptions
{
public Color[] TextColor { get; set; } = new Color[]
public MagickColor[] TextColor { get; set; } = new MagickColor[]
{
Color.Blue, Color.Black, Color.Black, Color.Brown, Color.Gray, Color.Green
MagickColors.Blue, MagickColors.Black, MagickColors.Black, MagickColors.Brown, MagickColors.Gray, MagickColors.Green
};
public Color[] DrawLinesColor { get; set; } = new Color[]
public MagickColor[] DrawLinesColor { get; set; } = new MagickColor[]
{
Color.Blue, Color.Black, Color.Black, Color.Brown, Color.Gray, Color.Green
MagickColors.Blue, MagickColors.Black, MagickColors.Black, MagickColors.Brown, MagickColors.Gray, MagickColors.Green
};
public float MinLineThickness { get; set; } = 0.7f;
@ -26,15 +24,15 @@ public class CaptchaOptions
public ushort NoiseRate { get; set; } = 500;
public Color[] NoiseRateColor { get; set; } = new Color[] { Color.Gray };
public MagickColor[] NoiseRateColor { get; set; } = new MagickColor[] { MagickColors.Gray };
public byte FontSize { get; set; } = 32;
public FontStyle FontStyle { get; set; } = FontStyle.Regular;
public FontStyleType FontStyle { get; set; } = FontStyleType.Normal;
public EncoderTypes EncoderType { get; set; } = EncoderTypes.Png;
public IImageEncoder Encoder => RandomTextGenerator.GetEncoder(EncoderType);
public MagickFormat Encoder => RandomTextGenerator.GetEncoder(EncoderType);
public byte DrawLines { get; set; } = 2;

12
modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/RandomTextGenerator.cs

@ -1,21 +1,19 @@
using System;
using System.Security.Cryptography;
using System.Text;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using ImageMagick;
namespace Volo.CmsKit.Public.Web.Security.Captcha;
public static class RandomTextGenerator
{
private static readonly char[] AllowedChars = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVXYZW23456789".ToCharArray();
public static IImageEncoder GetEncoder(EncoderTypes encoderType)
public static MagickFormat GetEncoder(EncoderTypes encoderType)
{
IImageEncoder encoder = encoderType switch
var encoder = encoderType switch
{
EncoderTypes.Png => new PngEncoder(),
EncoderTypes.Jpeg => new JpegEncoder(),
EncoderTypes.Png => MagickFormat.Png,
EncoderTypes.Jpeg => MagickFormat.Jpeg,
_ => throw new ArgumentException($"Encoder '{encoderType}' not found!")
};

134
modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs

@ -1,21 +1,13 @@
using System;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using Volo.Abp;
using Volo.CmsKit.Localization;
using Microsoft.Extensions.Localization;
using Volo.Abp.DependencyInjection;
using Color = SixLabors.ImageSharp.Color;
using PointF = SixLabors.ImageSharp.PointF;
using Volo.Abp.Caching;
using Microsoft.Extensions.Caching.Distributed;
using ImageMagick;
namespace Volo.CmsKit.Public.Web.Security.Captcha;
@ -108,93 +100,79 @@ public class SimpleMathsCaptchaGenerator : ITransientDependency
private byte[] GenerateInternal(string stringText, CaptchaOptions options)
{
byte[] result;
var random = new Random();
var fontName = MagickNET.FontNames.First();
var drawables = new Drawables()
.Font(fontName, options.FontStyle, FontWeight.Normal, FontStretch.Normal)
.FontPointSize(options.FontSize)
.StrokeColor(MagickColors.Transparent);
var size = (ushort)(drawables.FontTypeMetrics(stringText)?.TextWidth ?? 0);
using var image = new MagickImage(MagickColors.White, size + 15, options.Height);
using (var image = new Image<Rgba32>(options.Width, options.Height))
double position = 0;
var startWith = (byte)random.Next(5, 10);
foreach (var character in stringText)
{
float position = 0;
var random = new Random();
var startWith = (byte)random.Next(5, 10);
image.Mutate(ctx => ctx.BackgroundColor(Color.Transparent));
var fontFamily = SystemFonts.Families
.FirstOrDefault(x => x.GetAvailableStyles().Contains(options.FontStyle), SystemFonts.Families.First())
.Name;
var font = SystemFonts.CreateFont(fontFamily, options.FontSize, options.FontStyle);
foreach (var character in stringText)
{
var text = character.ToString();
var color = options.TextColor[random.Next(0, options.TextColor.Length)];
var location = new PointF(startWith + position, random.Next(6, 13));
image.Mutate(ctx => ctx.DrawText(text, font, color, location));
position += TextMeasurer.MeasureSize(character.ToString(), new TextOptions (font)
{
Origin = location
}).Width;
}
var text = character.ToString();
var color = options.TextColor[random.Next(0, options.TextColor.Length)];
drawables.FillColor(new MagickColor(color.R, color.G, color.B, color.A))
.Text(startWith + position,
RandomTextGenerator.GenerateNextFloat(image.BaseHeight / 2.3, image.BaseHeight / 1.7), text);
//add rotation
var rotation = GetRotation(options);
image.Mutate(ctx => ctx.Transform(rotation));
position += drawables.FontTypeMetrics(text)?.TextWidth ?? 0;
}
// add rotation
var rotation = GetRotation(options);
drawables.Rotation(rotation);
// add the dynamic image to original image
var size = (ushort)TextMeasurer.MeasureSize(stringText, new TextOptions(font)).Width;
var img = new Image<Rgba32>(size + 15, options.Height);
img.Mutate(ctx => ctx.BackgroundColor(Color.White));
drawables.Draw(image);
Parallel.For(0, options.DrawLines, i =>
Parallel.For(0, options.DrawLines, _ =>
{
// ReSharper disable once AccessToDisposedClosure
if (image is { IsDisposed: false })
{
var x0 = random.Next(0, random.Next(0, 30));
var y0 = random.Next(10, img.Height);
var y0 = random.Next(10, image.Height);
var x1 = random.Next(30, img.Width);
var y1 = random.Next(0, img.Height);
var x1 = random.Next(30, image.Width);
var y1 = random.Next(0, image.Height);
img.Mutate(ctx =>
ctx.DrawLine(options.TextColor[random.Next(0, options.TextColor.Length)],
RandomTextGenerator.GenerateNextFloat(options.MinLineThickness, options.MaxLineThickness),
new PointF[] { new PointF(x0, y0), new PointF(x1, y1) })
);
});
img.Mutate(ctx => ctx.DrawImage(image, 0.80f));
image.Draw(new Drawables()
.StrokeColor(options.DrawLinesColor[random.Next(0, options.DrawLinesColor.Length)])
.StrokeWidth(RandomTextGenerator.GenerateNextFloat(options.MinLineThickness,
options.MaxLineThickness))
.Line(x0, y0, x1, y1));
}
});
Parallel.For(0, options.NoiseRate, _ =>
Parallel.For(0, options.NoiseRate, _ =>
{
if (image is { IsDisposed: false })
{
var x0 = random.Next(0, img.Width - 1);
var y0 = random.Next(0, img.Height - 1);
img.Mutate(
ctx => ctx
.DrawLine(options.NoiseRateColor[random.Next(0, options.NoiseRateColor.Length)],
RandomTextGenerator.GenerateNextFloat(0.5, 1.5),
new PointF[] { new Vector2(x0, y0), new Vector2(x0 + 0.005f, y0 + 0.005f) })
var x = random.Next(0, image.Width);
var y = random.Next(0, image.Height);
image.Draw(new Drawables()
.FillColor(options.NoiseRateColor[random.Next(0, options.NoiseRateColor.Length)])
.Point(x, y)
);
});
img.Mutate(x =>
{
x.Resize(options.Width, options.Height);
});
using (var ms = new MemoryStream())
{
img.Save(ms, options.Encoder);
result = ms.ToArray();
}
}
});
return result;
image.Resize(new MagickGeometry(options.Width, options.Height) { IgnoreAspectRatio = true });
return image.ToByteArray(options.Encoder);
}
private static AffineTransformBuilder GetRotation(CaptchaOptions options)
private double GetRotation(CaptchaOptions options)
{
var random = new Random();
var width = random.Next(10, options.Width);
var height = random.Next(10, options.Height);
var pointF = new PointF(width, height);
var rotationDegrees = random.Next(0, options.MaxRotationDegrees);
return new AffineTransformBuilder().PrependRotationDegrees(rotationDegrees, pointF);
return rotationDegrees;
}
}

3
modules/cms-kit/src/Volo.CmsKit.Public.Web/Volo.CmsKit.Public.Web.csproj

@ -18,8 +18,7 @@
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" />
<PackageReference Include="Markdig.Signed" />
<PackageReference Include="HtmlSanitizer" />
<PackageReference Include="SixLabors.ImageSharp"/>
<PackageReference Include="SixLabors.ImageSharp.Drawing" />
<PackageReference Include="Magick.NET-Q16-AnyCPU" />
</ItemGroup>
<ItemGroup>

2
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml

@ -318,7 +318,7 @@
<select class="doc-section-combobox form-select"
aria-describedby="@("Section" + parameter.Name + "ComboboxAddonId")"
id="@("Section" + parameter.Name + "ComboboxId")" data-key="@parameter.Name">
@foreach (var value in parameter.Values)
@foreach (var value in parameter.Values.OrderBy(p => p.Value))
{
@if (value.Key == (Model.UserPreferences.ContainsKey(parameter.Name) ? Model.UserPreferences[parameter.Name] : null))
{

10
npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.html

@ -2,7 +2,13 @@
<hr class="my-3" />
<form *ngIf="form" [formGroup]="form" class="abp-md-form" (ngSubmit)="submit()" [validateOnSubmit]="true">
<form
*ngIf="form"
[formGroup]="form"
class="abp-md-form"
(ngSubmit)="submit()"
[validateOnSubmit]="true"
>
<div class="mb-3 form-group">
<label class="form-label"
>{{ 'AbpSettingManagement::DefaultFromDisplayName' | abpLocalization
@ -79,10 +85,10 @@
{{ 'AbpSettingManagement::Save' | abpLocalization }}
</button>
<button
*abpPermission="emailingPolicy"
type="button"
(click)="openSendEmailModal()"
class="btn btn-primary mx-2"
*abpPermission="emailingPolicy"
>
<i class="fa f-send" aria-hidden="true"></i>
{{ 'AbpSettingManagement::SendTestEmail' | abpLocalization }}

40
npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.ts

@ -1,11 +1,15 @@
import { NgbModalOptions } from '@ng-bootstrap/ng-bootstrap';
import { collapse, ToasterService } from '@abp/ng.theme.shared';
import { Component, OnInit } from '@angular/core';
import { Component, inject, OnInit } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { finalize } from 'rxjs/operators';
import { SettingManagementPolicyNames } from '../../enums/policy-names';
import { EmailSettingsService } from '@abp/ng.setting-management/proxy';
import { EmailSettingsDto } from '../../proxy/models';
import { ConfigStateService, LocalizationService } from '@abp/ng.core';
const { required, email } = Validators;
@Component({
selector: 'abp-email-setting-group',
@ -13,12 +17,18 @@ import { EmailSettingsDto } from '../../proxy/models';
animations: [collapse],
})
export class EmailSettingGroupComponent implements OnInit {
protected readonly localizationService = inject(LocalizationService);
protected readonly configStateSevice = inject(ConfigStateService);
protected readonly currentUserEmail = toSignal(
this.configStateSevice.getDeep$(['currentUser', 'email']),
);
form!: UntypedFormGroup;
emailTestForm: UntypedFormGroup;
saving = false;
emailingPolicy = SettingManagementPolicyNames.Emailing;
isEmailTestModalOpen = false;
modalSize:NgbModalOptions= { size:"lg"}
modalSize: NgbModalOptions = { size: 'lg' };
constructor(
private emailSettingsService: EmailSettingsService,
@ -62,30 +72,36 @@ export class EmailSettingGroupComponent implements OnInit {
this.getData();
});
}
openSendEmailModal() {
this.buildEmailTestForm();
this.isEmailTestModalOpen = true;
}
buildEmailTestForm() {
const { defaultFromAddress } = this.form.value || {};
const defaultSubject = this.localizationService.instant(
'AbpSettingManagement::TestEmailSubject',
...[Math.floor(Math.random() * 9999).toString()],
);
const defaultBody = this.localizationService.instant('AbpSettingManagement::TestEmailBody');
this.emailTestForm = this.fb.group({
senderEmailAddress: ['', [Validators.required, Validators.email]],
targetEmailAddress: ['', [Validators.required, Validators.email]],
subject: ['', [Validators.required]],
body: [''],
senderEmailAddress: [defaultFromAddress || '', [required, email]],
targetEmailAddress: [this.currentUserEmail(), [required, email]],
subject: [defaultSubject, [required]],
body: [defaultBody],
});
}
emailTestFormSubmit() {
if(this.emailTestForm.invalid){
if (this.emailTestForm.invalid) {
return;
}
this.emailSettingsService.sendTestEmail(this.emailTestForm.value).subscribe(res => {
this.emailSettingsService.sendTestEmail(this.emailTestForm.value).subscribe(res => {
this.toasterService.success('AbpSettingManagement::SuccessfullySent');
this.isEmailTestModalOpen = false;
})
});
}
}

3
npm/ng-packs/packages/setting-management/config/src/lib/enums/policy-names.ts

@ -1,4 +1,3 @@
export const enum SettingManagementPolicyNames {
Emailing = 'SettingManagement.Emailing',
}
}

19
npm/scripts/validate-versions.ts

@ -43,7 +43,7 @@ async function compare() {
!excludedPackages.includes(pkgJson.name) &&
pkgJson.version !== compareVersion
) {
throwError(pkgJsonPath, pkgJson.name);
throwError(pkgJsonPath, pkgJson.name, pkgJson.version);
}
const { dependencies, peerDependencies } = pkgJson;
@ -63,13 +63,15 @@ async function compareDependencies(
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
const packageName = entry[0];
const version = getCleanVersionName(entry[1]);
const cleanCompareVersion = getCleanVersionName(compareVersion);
if (
!excludedPackages.includes(entry[0]) &&
entry[0].match(/@(abp|volo)/)?.length &&
entry[1] !== `~${compareVersion}`
packageName.match(/@(abp|volo)/)?.length &&
version !== cleanCompareVersion
) {
throwError(filePath, entry[0], `~${compareVersion}`);
throwError(filePath, entry[0], cleanCompareVersion);
}
}
}
@ -77,6 +79,11 @@ async function compareDependencies(
function throwError(filePath: string, pkg: string, version?: string) {
const { compareVersion } = program.opts();
log.error(`${filePath}: ${pkg} version is not ${version || compareVersion}`);
log.error(`${filePath}: ${pkg} version is not ${compareVersion}. it is ${version}`);
process.exit(1);
}
function getCleanVersionName(version) {
// Remove caret (^) or tilde (~) from the beginning of the version number
return version.replace(/^[\^~]+/, '');
}
Loading…
Cancel
Save