Skip to content

Commit 37bb616

Browse files
committed
Add OCC.ViewCount module
1 parent 7f33b0e commit 37bb616

14 files changed

Lines changed: 198 additions & 2 deletions

OrchardCoreContrib.Modules.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCoreContrib.ContentP
7272
EndProject
7373
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCoreContrib.ContentPermissions.Tests", "test\OrchardCoreContrib.ContentPermissions.Tests\OrchardCoreContrib.ContentPermissions.Tests.csproj", "{2E878DD9-9D64-4EDF-A47C-7EBD71377AF0}"
7474
EndProject
75+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCoreContrib.ViewCount", "src\OrchardCoreContrib.ViewCount\OrchardCoreContrib.ViewCount.csproj", "{330877B1-7BE6-4B57-8714-2DADE1C53563}"
76+
EndProject
7577
Global
7678
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7779
Debug|Any CPU = Debug|Any CPU
@@ -186,6 +188,10 @@ Global
186188
{2E878DD9-9D64-4EDF-A47C-7EBD71377AF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
187189
{2E878DD9-9D64-4EDF-A47C-7EBD71377AF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
188190
{2E878DD9-9D64-4EDF-A47C-7EBD71377AF0}.Release|Any CPU.Build.0 = Release|Any CPU
191+
{330877B1-7BE6-4B57-8714-2DADE1C53563}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
192+
{330877B1-7BE6-4B57-8714-2DADE1C53563}.Debug|Any CPU.Build.0 = Debug|Any CPU
193+
{330877B1-7BE6-4B57-8714-2DADE1C53563}.Release|Any CPU.ActiveCfg = Release|Any CPU
194+
{330877B1-7BE6-4B57-8714-2DADE1C53563}.Release|Any CPU.Build.0 = Release|Any CPU
189195
EndGlobalSection
190196
GlobalSection(SolutionProperties) = preSolution
191197
HideSolutionNode = FALSE
@@ -218,6 +224,7 @@ Global
218224
{BE64AA1E-DDEF-405E-9004-6FF984DA6D71} = {A239BFB0-9BA7-467C-AD41-405D0740633F}
219225
{0BDB5C64-D4C3-454E-A54D-5F5A2169213B} = {C80A325F-F4C4-4C7B-A3CF-FB77CD8C9949}
220226
{2E878DD9-9D64-4EDF-A47C-7EBD71377AF0} = {A239BFB0-9BA7-467C-AD41-405D0740633F}
227+
{330877B1-7BE6-4B57-8714-2DADE1C53563} = {C80A325F-F4C4-4C7B-A3CF-FB77CD8C9949}
221228
EndGlobalSection
222229
GlobalSection(ExtensibilityGlobals) = postSolution
223230
SolutionGuid = {48F73B05-7D3D-4ACF-81AE-A98B2B4EFDB2}

src/OrchardCoreContrib.Modules.Web/OrchardCoreContrib.Modules.Web.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<ProjectReference Include="..\OrchardCoreContrib.Tenants\OrchardCoreContrib.Tenants.csproj" />
3131
<ProjectReference Include="..\OrchardCoreContrib.Themes.Admin\OrchardCoreContrib.Themes.Admin.csproj" />
3232
<ProjectReference Include="..\OrchardCoreContrib.Users\OrchardCoreContrib.Users.csproj" />
33+
<ProjectReference Include="..\OrchardCoreContrib.ViewCount\OrchardCoreContrib.ViewCount.csproj" />
3334
</ItemGroup>
3435

3536
</Project>

src/OrchardCoreContrib.Modules.Web/Recipes/OCC.recipe.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@
2525
"OrchardCoreContrib.Html",
2626
"OrchardCoreContrib.HealthChecks",
2727
"OrchardCoreContrib.Liquid",
28-
"OrchardCoreContrib.Users.Impersonation",
2928
"OrchardCore.Roles",
30-
"OrchardCore.Users",
3129
"OrchardCoreContrib.System",
30+
"OrchardCore.Users",
31+
"OrchardCoreContrib.Users.Impersonation",
32+
"OrchardCore.ViewCount",
3233
"TheTheme"
3334
]
3435
},
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using OrchardCore.ContentManagement.Display.ContentDisplay;
2+
using OrchardCore.ContentManagement.Display.Models;
3+
using OrchardCore.DisplayManagement.Views;
4+
using OrchardCoreContrib.ViewCount.Models;
5+
using OrchardCoreContrib.ViewCount.Services;
6+
using OrchardCoreContrib.ViewCount.ViewModels;
7+
8+
namespace OrchardCoreContrib.ViewCount.Drivers;
9+
10+
public sealed class ViewCountPartDisplayDriver(IViewCountService viewCountService) : ContentPartDisplayDriver<ViewCountPart>
11+
{
12+
public override IDisplayResult Display(ViewCountPart part, BuildPartDisplayContext context) => Initialize<ViewCountPartViewModel>(GetDisplayShapeType(context),
13+
async model =>
14+
{
15+
await viewCountService.ViewAsync(part.ContentItem);
16+
17+
model.Count = part.Count;
18+
}).Location("Detail", "Content:10");
19+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using OrchardCore.Modules.Manifest;
2+
using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants;
3+
4+
[assembly: Module(
5+
Name = "View Count",
6+
Author = ManifestConstants.Author,
7+
Website = ManifestConstants.Website,
8+
Version = "1.0.0",
9+
Description = "Allows to count the content item views.",
10+
Dependencies = ["OrchardCore.Contents"],
11+
Category = "Content Management"
12+
)]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using OrchardCore.ContentManagement.Metadata;
2+
using OrchardCore.ContentManagement.Metadata.Settings;
3+
using OrchardCore.Data.Migration;
4+
5+
namespace OrchardCoreContrib.ViewCount;
6+
7+
public class Migrations(IContentDefinitionManager contentDefinitionManager) : DataMigration
8+
{
9+
public async Task<int> CreateAsync()
10+
{
11+
await contentDefinitionManager.AlterPartDefinitionAsync("ViewCountPart", builder => builder
12+
.Attachable()
13+
.WithDescription("Allow to count the view number of your content item."));
14+
15+
return 1;
16+
}
17+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using OrchardCore.ContentManagement;
2+
3+
namespace OrchardCoreContrib.ViewCount.Models;
4+
public class ViewCountPart : ContentPart
5+
{
6+
public int Count { get; set; }
7+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Razor">
2+
3+
<PropertyGroup>
4+
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
5+
<VersionPrefix>1.0.0</VersionPrefix>
6+
<Authors>The Orchard Core Contrib Team</Authors>
7+
<Company />
8+
<Description>Allows to count the content item views.</Description>
9+
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
10+
<PackageProjectUrl>https://github.com/OrchardCoreContrib/OrchardCoreContrib.Modules/tree/main/src/OrchardCoreContrib.ViewCount/README.md</PackageProjectUrl>
11+
<RepositoryUrl>https://github.com/OrchardCoreContrib/OrchardCoreContrib.Modules</RepositoryUrl>
12+
<RepositoryType>git</RepositoryType>
13+
<PublishRepositoryUrl>true</PublishRepositoryUrl>
14+
<PackageTags>Orchard Core, Orchard Core Contrib, View Count, Counter</PackageTags>
15+
<PackageReleaseNotes>https://github.com/OrchardCoreContrib/OrchardCoreContrib.Modules/releases</PackageReleaseNotes>
16+
<PackageId>OrchardCoreContrib.ViewCount</PackageId>
17+
<PackageIcon>icon.png</PackageIcon>
18+
<Product>Orchard Core Contrib View Count Module</Product>
19+
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
20+
<Copyright>2019 Orchard Core Contrib</Copyright>
21+
</PropertyGroup>
22+
23+
<ItemGroup>
24+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
25+
</ItemGroup>
26+
27+
<ItemGroup>
28+
<None Include="../../images/icon.png" Pack="true" PackagePath="icon.png" />
29+
</ItemGroup>
30+
31+
<ItemGroup>
32+
<PackageReference Include="OrchardCore.Module.Targets" />
33+
<PackageReference Include="OrchardCore.ContentManagement" />
34+
<PackageReference Include="OrchardCore.ContentTypes.Abstractions" />
35+
<PackageReference Include="OrchardCore.DisplayManagement" />
36+
<PackageReference Include="OrchardCoreContrib.Abstractions" />
37+
<PackageReference Include="OrchardCoreContrib.Infrastructure.Abstractions" />
38+
</ItemGroup>
39+
40+
</Project>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using OrchardCore.ContentManagement;
2+
3+
namespace OrchardCoreContrib.ViewCount.Services;
4+
5+
public interface IViewCountService
6+
{
7+
int GetViewsCount(ContentItem contentItem);
8+
9+
Task ViewAsync(ContentItem contentItem);
10+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using Microsoft.Extensions.Logging;
2+
using OrchardCore.ContentManagement;
3+
using OrchardCore.Modules;
4+
using OrchardCoreContrib.Infrastructure;
5+
using OrchardCoreContrib.ViewCount.Handlers;
6+
using OrchardCoreContrib.ViewCount.Models;
7+
8+
namespace OrchardCoreContrib.ViewCount.Services;
9+
10+
public class ViewCountService(
11+
IContentManager contentManager,
12+
IEnumerable<IViewCountContentHandler> handlers,
13+
ILogger<ViewCountService> logger) : IViewCountService
14+
{
15+
public int GetViewsCount(ContentItem contentItem)
16+
{
17+
Guard.ArgumentNotNull(contentItem, nameof(contentItem));
18+
19+
var viewCountPart = contentItem.As<ViewCountPart>();
20+
21+
return viewCountPart?.Count ?? 0;
22+
}
23+
24+
public async Task ViewAsync(ContentItem contentItem)
25+
{
26+
Guard.ArgumentNotNull(contentItem, nameof(contentItem));
27+
28+
var viewCountPart = contentItem.As<ViewCountPart>()
29+
?? throw new InvalidOperationException($"The content item doesn't have a `{nameof(ViewCountPart)}`.");
30+
var count = viewCountPart.Count;
31+
var context = new ViewCountContentContext(contentItem, count);
32+
33+
await handlers.InvokeAsync((handler, context) => handler.ViewingAsync(context), context, logger);
34+
35+
contentItem.Content.ViewCountPart.Count = ++count;
36+
37+
await contentManager.UpdateAsync(contentItem);
38+
39+
context = new ViewCountContentContext(contentItem, count);
40+
41+
await handlers.InvokeAsync((handler, context) => handler.ViewedAsync(context), context, logger);
42+
}
43+
}

0 commit comments

Comments
 (0)