Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

URL Rewriting Module #16687

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
edcb175
Sync with upstream OrchardCMS/dev
arkadiuszwojcik Jul 10, 2020
ad39ce7
Merge pull request #3 from OrchardCMS/dev
arkadiuszwojcik Dec 17, 2020
67ff75e
Merge pull request #4 from OrchardCMS/dev
arkadiuszwojcik Dec 21, 2020
0c6761b
Merge pull request #5 from OrchardCMS/dev
arkadiuszwojcik Dec 27, 2020
f8ec4e2
Merge branch 'OrchardCMS:main' into dev
arkadiuszwojcik Sep 7, 2024
4661da6
Rewrite module
Sep 7, 2024
49f3939
Fix warning as errors
Sep 7, 2024
d7e6f61
Update OrchardCore.Rewrite.csproj
MikeAlhayek Sep 9, 2024
171c170
Code cleanup after code review
Sep 10, 2024
0f2914a
Rename module
Sep 11, 2024
3cbccfb
Rename classes to match module name
Sep 13, 2024
2eeefea
- Constant for module order
Sep 15, 2024
40bf27b
- Introduce ConfigureOptions
Sep 15, 2024
5a0a436
Merge branch 'OrchardCMS:main' into dev
arkadiuszwojcik Sep 16, 2024
3d86a84
Merge branch 'dev' into new_rewrite_module
Sep 16, 2024
6d1f4b4
UrlRewriting UI - part 1
Sep 18, 2024
ff64d23
Merge branch 'OrchardCMS:main' into dev
arkadiuszwojcik Sep 18, 2024
1735f9a
Merge branch 'dev' into new_rewrite_module
Sep 18, 2024
8080821
UrlRewriting UI - part 2
Sep 22, 2024
23546cb
UrlRewriting UI - part 3
Sep 25, 2024
060a19c
UrlRewriting UI - part 4
Sep 30, 2024
61e2ce7
Merge branch 'OrchardCMS:main' into dev
arkadiuszwojcik Sep 30, 2024
397ffa0
Merge branch 'dev' into new_rewrite_module
Sep 30, 2024
2963137
Add recipe step
Oct 2, 2024
7ffe421
Mark classes as sealed
Oct 2, 2024
806be17
Bug fixes
Oct 2, 2024
8b23ca1
UI fix
Oct 2, 2024
45d1547
Cleanup, add Id to Rules and other things
MikeAlhayek Oct 3, 2024
8fb929f
Merge branch 'main' into new_rewrite_module
MikeAlhayek Oct 3, 2024
78d7943
add site release warning
MikeAlhayek Oct 3, 2024
f5cd1f5
style
MikeAlhayek Oct 3, 2024
1f83775
Use Queries like UI and change everything
MikeAlhayek Oct 3, 2024
342d69b
remove old properties from RewriteStep
MikeAlhayek Oct 3, 2024
a1de614
missed method
MikeAlhayek Oct 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions OrchardCore.sln
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Queries.Core",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Sms.Azure", "src\OrchardCore.Modules\OrchardCore.Sms.Azure\OrchardCore.Sms.Azure.csproj", "{013C8BBF-6879-4B47-80C9-A466923E45E5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.UrlRewriting", "src\OrchardCore.Modules\OrchardCore.UrlRewriting\OrchardCore.UrlRewriting.csproj", "{D0F8B342-BDA8-44CB-AA43-7A65C79636A2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.UrlRewriting.Abstractions", "src\OrchardCore\OrchardCore.UrlRewriting.Abstractions\OrchardCore.UrlRewriting.Abstractions.csproj", "{675C8A76-C64F-47EC-B4F5-06D4F2D9662A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.UrlRewriting.Core", "src\OrchardCore\OrchardCore.UrlRewriting.Core\OrchardCore.UrlRewriting.Core.csproj", "{7B18DD99-A7BB-4297-8679-D87289758756}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1395,6 +1401,18 @@ Global
{013C8BBF-6879-4B47-80C9-A466923E45E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{013C8BBF-6879-4B47-80C9-A466923E45E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{013C8BBF-6879-4B47-80C9-A466923E45E5}.Release|Any CPU.Build.0 = Release|Any CPU
{D0F8B342-BDA8-44CB-AA43-7A65C79636A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D0F8B342-BDA8-44CB-AA43-7A65C79636A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D0F8B342-BDA8-44CB-AA43-7A65C79636A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D0F8B342-BDA8-44CB-AA43-7A65C79636A2}.Release|Any CPU.Build.0 = Release|Any CPU
{675C8A76-C64F-47EC-B4F5-06D4F2D9662A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{675C8A76-C64F-47EC-B4F5-06D4F2D9662A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{675C8A76-C64F-47EC-B4F5-06D4F2D9662A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{675C8A76-C64F-47EC-B4F5-06D4F2D9662A}.Release|Any CPU.Build.0 = Release|Any CPU
{7B18DD99-A7BB-4297-8679-D87289758756}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B18DD99-A7BB-4297-8679-D87289758756}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B18DD99-A7BB-4297-8679-D87289758756}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B18DD99-A7BB-4297-8679-D87289758756}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1636,6 +1654,9 @@ Global
{4BAA08A2-878C-4B96-86BF-5B3DB2B6C2C7} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
{61B358F2-702C-40AA-9DF7-7121248FE6DE} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
{013C8BBF-6879-4B47-80C9-A466923E45E5} = {A066395F-6F73-45DC-B5A6-B4E306110DCE}
{D0F8B342-BDA8-44CB-AA43-7A65C79636A2} = {A066395F-6F73-45DC-B5A6-B4E306110DCE}
{675C8A76-C64F-47EC-B4F5-06D4F2D9662A} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
{7B18DD99-A7BB-4297-8679-D87289758756} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {46A1D25A-78D1-4476-9CBF-25B75E296341}
Expand Down
30 changes: 30 additions & 0 deletions src/OrchardCore.Modules/OrchardCore.UrlRewriting/AdminMenu.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.Extensions.Localization;
using OrchardCore.Navigation;

namespace OrchardCore.UrlRewriting;

public sealed class AdminMenu : AdminNavigationProvider
{
internal readonly IStringLocalizer S;

public AdminMenu(IStringLocalizer<AdminMenu> stringLocalizer)
{
S = stringLocalizer;
}

protected override ValueTask BuildAsync(NavigationBuilder builder)
{
builder
.Add(S["Configuration"], configuration => configuration
.Add(S["URL Rewriting"], S["URL Rewriting"].PrefixPosition(), rewriting => rewriting
.AddClass("urlrewriting")
.Id("urlrewriting")
.Permission(UrlRewritingPermissions.ManageUrlRewriting)
.Action("Index", "Admin", "OrchardCore.UrlRewriting")
.LocalNav()
)
);

return ValueTask.CompletedTask;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using OrchardCore.Admin;
using OrchardCore.DisplayManagement;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Notify;
using OrchardCore.Environment.Shell;
using OrchardCore.Navigation;
using OrchardCore.Routing;
using OrchardCore.UrlRewriting.Models;
using OrchardCore.UrlRewriting.ViewModels;

namespace OrchardCore.UrlRewriting.Controllers;

[Admin("UrlRewriting/{action}/{id?}", "UrlRewriting{action}")]
public sealed class AdminController : Controller
{
private const string _optionsSearch = "Options.Search";

private readonly IAuthorizationService _authorizationService;
private readonly INotifier _notifier;
private readonly IDisplayManager<RewriteRule> _rewriteRuleDisplayManager;
private readonly IUpdateModelAccessor _updateModelAccessor;
private readonly IShellReleaseManager _shellReleaseManager;
private readonly IEnumerable<IUrlRewriteRuleSource> _urlRewritingRuleSources;
private readonly IRewriteRulesManager _rewriteRulesManager;

internal readonly IStringLocalizer S;
internal readonly IHtmlLocalizer H;

public AdminController(
IDisplayManager<RewriteRule> rewriteRuleDisplayManager,
IAuthorizationService authorizationService,
INotifier notifier,
IShellReleaseManager shellReleaseManager,
IEnumerable<IUrlRewriteRuleSource> urlRewritingRuleSources,
IRewriteRulesManager rewriteRulesManager,
IStringLocalizer<AdminController> stringLocalizer,
IHtmlLocalizer<AdminController> htmlLocalizer,
IUpdateModelAccessor updateModelAccessor)
{
_rewriteRuleDisplayManager = rewriteRuleDisplayManager;
_authorizationService = authorizationService;
_notifier = notifier;
_shellReleaseManager = shellReleaseManager;
_urlRewritingRuleSources = urlRewritingRuleSources;
_rewriteRulesManager = rewriteRulesManager;
_updateModelAccessor = updateModelAccessor;
S = stringLocalizer;
H = htmlLocalizer;
}

public async Task<IActionResult> Index(
RewriteRuleOptions options,
PagerParameters pagerParameters,
[FromServices] IShapeFactory shapeFactory,
[FromServices] IOptions<PagerOptions> pagerOptions)
{
if (!await _authorizationService.AuthorizeAsync(User, UrlRewritingPermissions.ManageUrlRewriting))
{
return Forbid();
}

var pager = new Pager(pagerParameters, pagerOptions.Value.GetPageSize());

// Maintain previous route data when generating page links.
var routeData = new RouteData();

if (!string.IsNullOrEmpty(options.Search))
{
routeData.Values.TryAdd(_optionsSearch, options.Search);
}

var result = await _rewriteRulesManager.PageQueriesAsync(pager.Page, pager.PageSize, new RewriteRulesQueryContext()
{
Name = options.Search,
});

var model = new ListRewriteRuleViewModel
{
Rules = [],
Options = options,
Pager = await shapeFactory.PagerAsync(pager, result.Count, routeData),
SourceNames = _urlRewritingRuleSources.Select(x => x.Name),
};

foreach (var rule in result.Records)
{
model.Rules.Add(new RewriteRuleEntry
{
Rule = rule,
Shape = await _rewriteRuleDisplayManager.BuildDisplayAsync(rule, _updateModelAccessor.ModelUpdater, "SummaryAdmin")
});
}

model.Options.BulkActions =
[
new SelectListItem(S["Delete"], nameof(RewriteRuleAction.Remove)),
];

return View(model);
}

[HttpPost]
[ActionName(nameof(Index))]
[FormValueRequired("submit.Filter")]
public ActionResult IndexFilterPOST(ListRewriteRuleViewModel model)
=> RedirectToAction(nameof(Index), new RouteValueDictionary
{
{ _optionsSearch, model.Options.Search }
});

public async Task<ActionResult> Create(string id)
{
if (!await _authorizationService.AuthorizeAsync(User, UrlRewritingPermissions.ManageUrlRewriting))
{
return Forbid();
}

var rule = await _rewriteRulesManager.NewAsync(id);

var shape = await _rewriteRuleDisplayManager.BuildEditorAsync(rule, _updateModelAccessor.ModelUpdater, isNew: true);

return View(shape);
}

[HttpPost]
[ActionName(nameof(Create))]
public async Task<ActionResult> CreatePOST(string id)
{
if (!await _authorizationService.AuthorizeAsync(User, UrlRewritingPermissions.ManageUrlRewriting))
{
return Forbid();
}

var rule = await _rewriteRulesManager.NewAsync(id);

var shape = await _rewriteRuleDisplayManager.UpdateEditorAsync(rule, _updateModelAccessor.ModelUpdater, isNew: true);

if (ModelState.IsValid)
{
await _rewriteRulesManager.SaveAsync(rule);

await _notifier.SuccessAsync(H["Rule created successfully."]);

return RedirectToAction(nameof(Index));
}

_shellReleaseManager.SuspendReleaseRequest();

return View(shape);
}

public async Task<ActionResult> Edit(string id)
{
if (!await _authorizationService.AuthorizeAsync(User, UrlRewritingPermissions.ManageUrlRewriting))
{
return Forbid();
}

var rule = await _rewriteRulesManager.FindByIdAsync(id);

if (rule == null)
{
return NotFound();
}

var shape = await _rewriteRuleDisplayManager.BuildEditorAsync(rule, _updateModelAccessor.ModelUpdater, isNew: false);

return View(shape);
}

[HttpPost]
[ActionName(nameof(Edit))]
public async Task<ActionResult> EditPOST(string id)
{
if (!await _authorizationService.AuthorizeAsync(User, UrlRewritingPermissions.ManageUrlRewriting))
{
return Forbid();
}

var rule = await _rewriteRulesManager.FindByIdAsync(id);

if (rule == null)
{
return NotFound();
}

var shape = await _rewriteRuleDisplayManager.UpdateEditorAsync(rule, _updateModelAccessor.ModelUpdater, isNew: false);

if (ModelState.IsValid)
{
await _rewriteRulesManager.SaveAsync(rule);

await _notifier.SuccessAsync(H["Rule updated successfully."]);

return RedirectToAction(nameof(Index));
}

_shellReleaseManager.SuspendReleaseRequest();

return View(shape);
}

[HttpPost]
public async Task<IActionResult> Delete(string id)
{
if (!await _authorizationService.AuthorizeAsync(User, UrlRewritingPermissions.ManageUrlRewriting))
{
return Forbid();
}

var rule = await _rewriteRulesManager.FindByIdAsync(id);

if (rule == null)
{
return NotFound();
}

await _rewriteRulesManager.DeleteAsync(rule);

_shellReleaseManager.RequestRelease();

await _notifier.SuccessAsync(H["Rule deleted successfully."]);

return RedirectToAction(nameof(Index));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using Microsoft.Extensions.Localization;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Mvc.ModelBinding;
using OrchardCore.UrlRewriting;
using OrchardCore.UrlRewriting.Models;
using OrchardCore.UrlRewriting.ViewModels;

namespace OrchardCore.Queries.Drivers;

public sealed class RewriteRulesDisplayDriver : DisplayDriver<RewriteRule>
{
private readonly IRewriteRulesManager _rulesManager;

internal readonly IStringLocalizer S;

public RewriteRulesDisplayDriver(
IRewriteRulesManager rulesManager,
IStringLocalizer<RewriteRulesDisplayDriver> stringLocalizer)
{
_rulesManager = rulesManager;
S = stringLocalizer;
}

public override Task<IDisplayResult> DisplayAsync(RewriteRule rule, BuildDisplayContext context)
{
return CombineAsync(
Dynamic("RewriteRule_Fields_SummaryAdmin", model =>
{
model.Name = rule.Name;
model.Source = rule.Source;
model.Rule = rule;
}).Location("Content:1"),
Dynamic("RewriteRule_Buttons_SummaryAdmin", model =>
{
model.Name = rule.Name;
model.Source = rule.Source;
model.Rule = rule;
}).Location("Actions:5")
);
}

public override Task<IDisplayResult> EditAsync(RewriteRule rule, BuildEditorContext context)
{
return CombineAsync(
Initialize<EditRewriteRuleViewModel>("RewriteRule_Fields_Edit", model =>
{
model.Name = rule.Name;
model.SkipFurtherRules = rule.SkipFurtherRules;
model.Source = rule.Source;
model.Rule = rule;
}).Location("Content:1"),
Initialize<EditRewriteRuleViewModel>("RewriteRule_Fields_Buttons", model =>
{
model.Name = rule.Name;
model.Source = rule.Source;
model.SkipFurtherRules = rule.SkipFurtherRules;
model.Rule = rule;
}).Location("Actions:5")
);
}

public override async Task<IDisplayResult> UpdateAsync(RewriteRule rule, UpdateEditorContext context)
{
await context.Updater.TryUpdateModelAsync(rule, Prefix,
m => m.Name,
m => m.SkipFurtherRules,
m => m.Source);

if (string.IsNullOrEmpty(rule.Name))
{
context.Updater.ModelState.AddModelError(Prefix, nameof(rule.Name), S["Name is required"]);
}

return await EditAsync(rule, context);
}
}
Loading