Skip to content

Commit d2144da

Browse files
authored
Integrate PageViewStats in the Content Items view in the backend (#4)
* Fix missing referer in SQL statement
1 parent 417138d commit d2144da

7 files changed

Lines changed: 119 additions & 10 deletions

File tree

Neolution.OrchardCoreModules.PageViewStats/Controllers/CountPageViewController.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,15 @@ public async Task<ActionResult> IndexPost(string contentItemId)
8282
$" {dialect.QuoteForColumnName(nameof(PageView.ContentItemId))}, " +
8383
$" {dialect.QuoteForColumnName(nameof(PageView.RequestIpAddress))}, " +
8484
$" {dialect.QuoteForColumnName(nameof(PageView.RequestUserAgentString))}, " +
85+
$" {dialect.QuoteForColumnName(nameof(PageView.RequestReferer))}, " +
8586
$" {dialect.QuoteForColumnName(nameof(PageView.RequestUserAgentIsRobot))}) " +
8687
$"VALUES (" +
8788
$" @{nameof(PageView.Id)}, " +
8889
$" @{nameof(PageView.CreatedUtc)}, " +
8990
$" @{nameof(PageView.ContentItemId)}, " +
9091
$" @{nameof(PageView.RequestIpAddress)}, " +
9192
$" @{nameof(PageView.RequestUserAgentString)}, " +
93+
$" @{nameof(PageView.RequestReferer)}, " +
9294
$" @{nameof(PageView.RequestUserAgentIsRobot)});";
9395

9496
await connection.ExecuteAsync(insertCmd, pageView);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
namespace Neolution.OrchardCoreModules.PageViewStats.Drivers
2+
{
3+
using OrchardCore.ContentManagement.Display.ContentDisplay;
4+
using OrchardCore.DisplayManagement.ModelBinding;
5+
using OrchardCore.DisplayManagement.Views;
6+
using System;
7+
using System.Linq;
8+
using System.Threading.Tasks;
9+
using OrchardCore.ContentManagement;
10+
using OrchardCore.Settings;
11+
using Neolution.OrchardCoreModules.PageViewStats.Services;
12+
using Microsoft.AspNetCore.Authorization;
13+
using Microsoft.AspNetCore.Http;
14+
using OrchardCore.Admin;
15+
16+
public class PageViewStatsContentDisplayDriver : ContentDisplayDriver
17+
{
18+
private readonly IHttpContextAccessor httpContextAccessor;
19+
private readonly IAuthorizationService authorizationService;
20+
private readonly ISiteService siteService;
21+
private readonly IPageViewsRepository repository;
22+
23+
public PageViewStatsContentDisplayDriver(IHttpContextAccessor httpContextAccessor, IAuthorizationService authorizationService, ISiteService siteService, IPageViewsRepository repository)
24+
{
25+
this.httpContextAccessor = httpContextAccessor;
26+
this.authorizationService = authorizationService;
27+
this.siteService = siteService;
28+
this.repository = repository;
29+
}
30+
31+
public override async Task<IDisplayResult> DisplayAsync(ContentItem contentItem, IUpdateModel updater)
32+
{
33+
var context = this.httpContextAccessor.HttpContext;
34+
35+
// Should only render on the back-end
36+
if (!AdminAttribute.IsApplied(context))
37+
{
38+
return null;
39+
}
40+
41+
// Should only render for users with proper permissions
42+
if (!await authorizationService.AuthorizeAsync(context?.User, PageViewStatsPermissions.ViewPageViewStats).ConfigureAwait(false))
43+
{
44+
return null;
45+
}
46+
47+
var settings = await this.siteService.GetSiteSettingsAsync().ConfigureAwait(false);
48+
var tz = TimeZoneInfo.FindSystemTimeZoneById(settings.TimeZoneId);
49+
var now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tz);
50+
var today = DateOnly.FromDateTime(now);
51+
52+
var pageViews = await this.repository.LoadPageViewsAsync(today.AddDays(-30), today).ConfigureAwait(false);
53+
var contentPageViews = pageViews.SelectMany(x => x.PageViews).Where(x => x.ContentItemId == contentItem.ContentItemId).ToList();
54+
var totalViews = await this.repository.LoadAllPageViewsAsync().ConfigureAwait(false);
55+
var contentPageTotalViews = totalViews.SelectMany(x => x.PageViews).Where(x => x.ContentItemId == contentItem.ContentItemId).ToList();
56+
57+
return Initialize<PageViewStatsContentDisplayViewModel>("PageViewStatsPart_SummaryAdmin", m =>
58+
{
59+
m.DailyViews = contentPageViews.Select(x => x.TotalViews).FirstOrDefault();
60+
m.MonthlyViews = contentPageViews.Sum(x => x.TotalViews);
61+
m.TotalViews = contentPageTotalViews.Sum(x => x.TotalViews);
62+
})
63+
.Location("SummaryAdmin", "Meta:90");
64+
}
65+
}
66+
67+
public class PageViewStatsContentDisplayViewModel
68+
{
69+
public int DailyViews { get; set; }
70+
public int MonthlyViews { get; set; }
71+
public int TotalViews { get; set; }
72+
}
73+
}

Neolution.OrchardCoreModules.PageViewStats/Drivers/PageViewStatsSettingsDisplayDriver.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@ public PageViewStatsSettingsDisplayDriver(IHttpContextAccessor httpContextAccess
2121
_httpContextAccessor = httpContextAccessor;
2222
_authorizationService = authorizationService;
2323
}
24-
24+
2525
public override async Task<IDisplayResult> EditAsync(PageViewStatsSettings settings, BuildEditorContext context)
2626
{
2727
var user = _httpContextAccessor.HttpContext?.User;
28-
2928
if (!await _authorizationService.AuthorizeAsync(user, PageViewStatsPermissions.ManagePageViewStats))
3029
{
3130
return null;

Neolution.OrchardCoreModules.PageViewStats/Services/PageViewsRepository.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public async Task<DailyArchive> CreateAggregateAsync(DateOnly date)
6161

6262
public interface IPageViewsRepository
6363
{
64+
Task<IList<DailyArchive>> LoadAllPageViewsAsync();
6465
Task<IList<DailyArchive>> LoadPageViewsAsync(DateOnly earliest, DateOnly latest);
6566
}
6667

@@ -77,6 +78,27 @@ public PageViewsRepository(ISiteService siteService, IAggregateService aggregate
7778
this.documentManager = documentManager;
7879
}
7980

81+
public async Task<IList<DailyArchive>> LoadAllPageViewsAsync()
82+
{
83+
var pageViewArchive = await documentManager.GetOrCreateImmutableAsync();
84+
var result = pageViewArchive.DailyArchives;
85+
86+
var settings = await this.siteService.GetSiteSettingsAsync();
87+
var today = DateOnlyExtensions.Today(settings);
88+
89+
var isTodayIncluded = pageViewArchive.DailyArchives.Any(x => x.Id == today.ToString("yyyy-MM-dd"));
90+
if (!isTodayIncluded)
91+
{
92+
var todayViewArchive = await LoadPageViewsAsync(today.AddDays(-1), today).ConfigureAwait(false);
93+
if (todayViewArchive.Any())
94+
{
95+
result.Insert(0, todayViewArchive.First());
96+
}
97+
}
98+
99+
return result;
100+
}
101+
80102
public async Task<IList<DailyArchive>> LoadPageViewsAsync(DateOnly earliest, DateOnly latest)
81103
{
82104
var settings = await this.siteService.GetSiteSettingsAsync();

Neolution.OrchardCoreModules.PageViewStats/Startup.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace Neolution.OrchardCoreModules.PageViewStats;
2020
using OrchardCore.Settings;
2121
using AdminMenu = Neolution.OrchardCoreModules.PageViewStats.Navigation.AdminMenu;
2222
using MediatR;
23-
23+
using OrchardCore.ContentManagement.Display.ContentDisplay;
2424

2525
public class Startup : StartupBase
2626
{
@@ -44,6 +44,8 @@ public override void ConfigureServices(IServiceCollection services)
4444
services.AddScoped<IPageViewsRepository, PageViewsRepository>();
4545
services.AddScoped<IAggregateService, AggregateService>();
4646

47+
services.AddScoped<IContentDisplayDriver, PageViewStatsContentDisplayDriver>();
48+
4749
services.AddMediatR(typeof(Startup));
4850

4951
services.AddSingleton<IBackgroundTask, ArchivePageViewsBackgroundTask>();

Neolution.OrchardCoreModules.PageViewStats/Views/Dashboard/Index.cshtml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
<div class="form-group d-inline-flex float-right mb-1">
77
<div class="btn-group">
88
<div class="dropdown order-md-1">
9-
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" id="new-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
9+
<button type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
1010
Last @Model.History days
1111
</button>
12-
<div class="dropdown-menu dropdown-menu-right scrollable" aria-labelledby="bulk-action-menu-button">
13-
<a class="dropdown-item" href="?history=7">Last week</a>
14-
<a class="dropdown-item" href="?history=14">Last two weeks</a>
15-
<a class="dropdown-item" href="?history=21">Last three weeks</a>
16-
<a class="dropdown-item" href="?history=30">Last month</a>
17-
</div>
12+
<ul class="dropdown-menu">
13+
<li><a class="dropdown-item" href="?history=7">Last week</a></li>
14+
<li><a class="dropdown-item" href="?history=14">Last two weeks</a></li>
15+
<li><a class="dropdown-item" href="?history=21">Last three weeks</a></li>
16+
<li><a class="dropdown-item" href="?history=30">Last month</a></li>
17+
</ul>
1818
</div>
1919
</div>
2020
</div>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@model Neolution.OrchardCoreModules.PageViewStats.Drivers.PageViewStatsContentDisplayViewModel
2+
3+
<span class="badge rounded-pill bg-light text-dark">
4+
<i class="fa fa-chart-bar text-info" aria-hidden="true"></i> Today: @Model.DailyViews
5+
</span>
6+
<span class="badge rounded-pill bg-light text-dark">
7+
<i class="fa fa-chart-bar text-info" aria-hidden="true"></i> This Month: @Model.MonthlyViews
8+
</span>
9+
<span class="badge rounded-pill bg-light text-dark">
10+
<i class="fa fa-chart-bar text-info" aria-hidden="true"></i> Total: @Model.TotalViews
11+
</span>

0 commit comments

Comments
 (0)