mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-04-05 21:01:35 +08:00
Adding the Reports feature back.
This commit is contained in:
parent
95eecd30b9
commit
ad4a702f7c
@ -223,6 +223,11 @@
|
|||||||
<Compile Include="Navigation\ViewModels\MenuItemEntry.cs" />
|
<Compile Include="Navigation\ViewModels\MenuItemEntry.cs" />
|
||||||
<Compile Include="Navigation\ViewModels\NavigationManagementViewModel.cs" />
|
<Compile Include="Navigation\ViewModels\NavigationManagementViewModel.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Reports\AdminMenu.cs" />
|
||||||
|
<Compile Include="Reports\Controllers\AdminController.cs" />
|
||||||
|
<Compile Include="Reports\Routes.cs" />
|
||||||
|
<Compile Include="Reports\ViewModels\DisplayReportViewModel.cs" />
|
||||||
|
<Compile Include="Reports\ViewModels\ReportsAdminIndexViewModel.cs" />
|
||||||
<Compile Include="Scheduling\Migrations.cs" />
|
<Compile Include="Scheduling\Migrations.cs" />
|
||||||
<Compile Include="Scheduling\Models\ScheduledTaskRecord.cs" />
|
<Compile Include="Scheduling\Models\ScheduledTaskRecord.cs" />
|
||||||
<Compile Include="Scheduling\Services\ScheduledTaskManager.cs" />
|
<Compile Include="Scheduling\Services\ScheduledTaskManager.cs" />
|
||||||
@ -310,6 +315,9 @@
|
|||||||
<Content Include="Navigation\Styles\navigation-admin.css" />
|
<Content Include="Navigation\Styles\navigation-admin.css" />
|
||||||
<Content Include="Navigation\Styles\images\menu.navigation.png" />
|
<Content Include="Navigation\Styles\images\menu.navigation.png" />
|
||||||
<Content Include="Navigation\Styles\menu.navigation-admin.css" />
|
<Content Include="Navigation\Styles\menu.navigation-admin.css" />
|
||||||
|
<Content Include="Reports\Module.txt" />
|
||||||
|
<Content Include="Reports\Styles\images\menu.reports.png" />
|
||||||
|
<Content Include="Reports\Styles\menu.reports-admin.css" />
|
||||||
<Content Include="Settings\Module.txt" />
|
<Content Include="Settings\Module.txt" />
|
||||||
<Content Include="Settings\Styles\admin.css" />
|
<Content Include="Settings\Styles\admin.css" />
|
||||||
<Content Include="Settings\Styles\images\menu.settings.png" />
|
<Content Include="Settings\Styles\images\menu.settings.png" />
|
||||||
@ -557,6 +565,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Common\Views\EditorTemplates\Flavor.cshtml" />
|
<Content Include="Common\Views\EditorTemplates\Flavor.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Reports\Styles\Web.config" />
|
||||||
|
<Content Include="Reports\Views\Admin\Display.cshtml" />
|
||||||
|
<Content Include="Reports\Views\Admin\Index.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
17
src/Orchard.Web/Core/Reports/AdminMenu.cs
Normal file
17
src/Orchard.Web/Core/Reports/AdminMenu.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Orchard.Localization;
|
||||||
|
using Orchard.Security;
|
||||||
|
using Orchard.UI.Navigation;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Reports {
|
||||||
|
public class AdminMenu : INavigationProvider {
|
||||||
|
public Localizer T { get; set; }
|
||||||
|
public string MenuName { get { return "admin"; } }
|
||||||
|
|
||||||
|
public void GetNavigation(NavigationBuilder builder) {
|
||||||
|
builder.AddImageSet("reports")
|
||||||
|
.Add(T("Reports"), "12",
|
||||||
|
menu => menu.Add(T("View"), "0", item => item.Action("Index", "Admin", new { area = "Reports" })
|
||||||
|
.Permission(StandardPermissions.SiteOwner)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
src/Orchard.Web/Core/Reports/Controllers/AdminController.cs
Normal file
42
src/Orchard.Web/Core/Reports/Controllers/AdminController.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using Orchard.Core.Reports.ViewModels;
|
||||||
|
using Orchard.Localization;
|
||||||
|
using Orchard.Reports.Services;
|
||||||
|
using Orchard.Security;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Reports.Controllers {
|
||||||
|
public class AdminController : Controller {
|
||||||
|
private readonly IReportsManager _reportsManager;
|
||||||
|
|
||||||
|
public AdminController(
|
||||||
|
IOrchardServices services,
|
||||||
|
IReportsManager reportsManager) {
|
||||||
|
Services = services;
|
||||||
|
_reportsManager = reportsManager;
|
||||||
|
T = NullLocalizer.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOrchardServices Services { get; set; }
|
||||||
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
|
public ActionResult Index() {
|
||||||
|
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list reports")))
|
||||||
|
return new HttpUnauthorizedResult();
|
||||||
|
|
||||||
|
var model = new ReportsAdminIndexViewModel { Reports = _reportsManager.GetReports().ToList() };
|
||||||
|
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionResult Display(int id) {
|
||||||
|
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to display report")))
|
||||||
|
return new HttpUnauthorizedResult();
|
||||||
|
|
||||||
|
var model = new DisplayReportViewModel { Report = _reportsManager.Get(id) };
|
||||||
|
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
9
src/Orchard.Web/Core/Reports/Module.txt
Normal file
9
src/Orchard.Web/Core/Reports/Module.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Name: Reports
|
||||||
|
AntiForgery: enabled
|
||||||
|
Author: The Orchard Team
|
||||||
|
Website: http://orchardproject.net
|
||||||
|
Version: 1.9.1
|
||||||
|
OrchardVersion: 1.9
|
||||||
|
Description: The dashboard module is providing the reports screen of the application.
|
||||||
|
FeatureDescription: Reports management (deprecated).
|
||||||
|
Category: Core
|
33
src/Orchard.Web/Core/Reports/Routes.cs
Normal file
33
src/Orchard.Web/Core/Reports/Routes.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using System.Web.Routing;
|
||||||
|
using Orchard.Mvc.Routes;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Reports {
|
||||||
|
public class Routes : IRouteProvider {
|
||||||
|
public void GetRoutes(ICollection<RouteDescriptor> routes) {
|
||||||
|
foreach (var routeDescriptor in GetRoutes())
|
||||||
|
routes.Add(routeDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<RouteDescriptor> GetRoutes() {
|
||||||
|
return new[] {
|
||||||
|
new RouteDescriptor {
|
||||||
|
Priority = -5,
|
||||||
|
Route = new Route(
|
||||||
|
"Admin/Reports",
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"area", "Reports"},
|
||||||
|
{"controller", "Admin"},
|
||||||
|
{"action", "Index"}
|
||||||
|
},
|
||||||
|
new RouteValueDictionary(),
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"area", "Reports"}
|
||||||
|
},
|
||||||
|
new MvcRouteHandler())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/Orchard.Web/Core/Reports/Styles/Web.config
Normal file
16
src/Orchard.Web/Core/Reports/Styles/Web.config
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<staticContent>
|
||||||
|
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
|
||||||
|
</staticContent>
|
||||||
|
|
||||||
|
<handlers accessPolicy="Script,Read">
|
||||||
|
<!--
|
||||||
|
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||||
|
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||||
|
-->
|
||||||
|
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||||
|
</handlers>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
BIN
src/Orchard.Web/Core/Reports/Styles/images/menu.reports.png
Normal file
BIN
src/Orchard.Web/Core/Reports/Styles/images/menu.reports.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 219 B |
@ -0,0 +1,6 @@
|
|||||||
|
.navicon-reports {
|
||||||
|
background-image:url(images/menu.reports.png) !important;
|
||||||
|
}
|
||||||
|
.navicon-reports:hover {
|
||||||
|
background-position:0 -30px !important;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
using Orchard.Reports;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Reports.ViewModels {
|
||||||
|
public class DisplayReportViewModel {
|
||||||
|
public Report Report { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Orchard.Reports;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Reports.ViewModels {
|
||||||
|
public class ReportsAdminIndexViewModel {
|
||||||
|
public IList<Report> Reports { get; set; }
|
||||||
|
}
|
||||||
|
}
|
39
src/Orchard.Web/Core/Reports/Views/Admin/Display.cshtml
Normal file
39
src/Orchard.Web/Core/Reports/Views/Admin/Display.cshtml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
@model DisplayReportViewModel
|
||||||
|
@using Orchard.Core.Reports.ViewModels;
|
||||||
|
|
||||||
|
@{ Layout.Title = T("Display Report").ToString(); }
|
||||||
|
|
||||||
|
@using(Html.BeginFormAntiForgeryPost()) {
|
||||||
|
@Html.ValidationSummary()
|
||||||
|
<fieldset>
|
||||||
|
<table class="items" summary="@T("This is a table of the reports in your application")">
|
||||||
|
<colgroup>
|
||||||
|
<col id="Col1" />
|
||||||
|
<col id="Col2" />
|
||||||
|
<col id="Col3" />
|
||||||
|
<col id="Col4" />
|
||||||
|
</colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">@T("Type")</th>
|
||||||
|
<th scope="col">@T("Message")</th>
|
||||||
|
<th scope="col">@T("Date")</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
@foreach (var reportEntry in Model.Report.Entries) {
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
@reportEntry.Type
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@reportEntry.Message
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@reportEntry.Utc.ToLocalTime().ToShortDateString() @reportEntry.Utc.ToLocalTime().ToShortTimeString()
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
||||||
|
}
|
39
src/Orchard.Web/Core/Reports/Views/Admin/Index.cshtml
Normal file
39
src/Orchard.Web/Core/Reports/Views/Admin/Index.cshtml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
@model ReportsAdminIndexViewModel
|
||||||
|
@using Orchard.Core.Reports.ViewModels;
|
||||||
|
|
||||||
|
@{ Layout.Title = T("Reports").ToString(); }
|
||||||
|
|
||||||
|
@using(Html.BeginFormAntiForgeryPost()) {
|
||||||
|
@Html.ValidationSummary()
|
||||||
|
<fieldset>
|
||||||
|
<table class="items" summary="@T("This is a table of the reports in your application")">
|
||||||
|
<colgroup>
|
||||||
|
<col id="Col1" />
|
||||||
|
<col id="Col2" />
|
||||||
|
<col id="Col3" />
|
||||||
|
<col id="Col4" />
|
||||||
|
</colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">@T("Name")</th>
|
||||||
|
<th scope="col">@T("Title")</th>
|
||||||
|
<th scope="col">@T("Date")</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
@foreach (var report in Model.Reports) {
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
@Html.ActionLink(report.ActivityName, "Display", new {id = report.ReportId})
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@report.Title
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@report.Utc.ToLocalTime().ToShortDateString() @report.Utc.ToLocalTime().ToShortTimeString()
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
||||||
|
}
|
@ -149,6 +149,15 @@
|
|||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Reports\Report.cs" />
|
||||||
|
<Compile Include="Reports\ReportEntry.cs" />
|
||||||
|
<Compile Include="Reports\ReportExtentions.cs" />
|
||||||
|
<Compile Include="Reports\Services\IReportsCoordinator.cs" />
|
||||||
|
<Compile Include="Reports\Services\IReportsManager.cs" />
|
||||||
|
<Compile Include="Reports\Services\IReportsPersister.cs" />
|
||||||
|
<Compile Include="Reports\Services\ReportsCoordinator.cs" />
|
||||||
|
<Compile Include="Reports\Services\ReportsManager.cs" />
|
||||||
|
<Compile Include="Reports\Services\ReportsPersister.cs" />
|
||||||
<Compile Include="Security\IMembershipValidationService.cs" />
|
<Compile Include="Security\IMembershipValidationService.cs" />
|
||||||
<Compile Include="Localization\Services\ILocalizationStreamParser.cs" />
|
<Compile Include="Localization\Services\ILocalizationStreamParser.cs" />
|
||||||
<Compile Include="Localization\Services\LocalizationStreamParser.cs" />
|
<Compile Include="Localization\Services\LocalizationStreamParser.cs" />
|
||||||
|
16
src/Orchard/Reports/Report.cs
Normal file
16
src/Orchard/Reports/Report.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Orchard.Reports {
|
||||||
|
public class Report {
|
||||||
|
public Report() {
|
||||||
|
Entries = new List<ReportEntry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<ReportEntry> Entries { get; set;}
|
||||||
|
public int ReportId { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string ActivityName { get; set; }
|
||||||
|
public DateTime Utc { get; set; }
|
||||||
|
}
|
||||||
|
}
|
15
src/Orchard/Reports/ReportEntry.cs
Normal file
15
src/Orchard/Reports/ReportEntry.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Orchard.Reports {
|
||||||
|
public enum ReportEntryType {
|
||||||
|
Information,
|
||||||
|
Warning,
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReportEntry {
|
||||||
|
public ReportEntryType Type { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public DateTime Utc { get; set; }
|
||||||
|
}
|
||||||
|
}
|
35
src/Orchard/Reports/ReportExtentions.cs
Normal file
35
src/Orchard/Reports/ReportExtentions.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using Orchard.Reports;
|
||||||
|
using Orchard.Reports.Services;
|
||||||
|
|
||||||
|
public static class ReportExtentions {
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new report entry of type information to a report that was previously registered.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="Register()"/>
|
||||||
|
/// <param name="reportKey">Key, i.e. technical name of the report. Should be the same as the one used when registering the report.</param>
|
||||||
|
/// <param name="message">The message to include in the entry.</param>
|
||||||
|
public static void Information(this IReportsCoordinator reportCoordinator, string reportKey, string message) {
|
||||||
|
reportCoordinator.Add(reportKey, ReportEntryType.Information, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new report entry of type warning to a report that was previously registered.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="Register()"/>
|
||||||
|
/// <param name="reportKey">Key, i.e. technical name of the report. Should be the same as the one used when registering the report.</param>
|
||||||
|
/// <param name="message">The message to include in the entry.</param>
|
||||||
|
public static void Warning(this IReportsCoordinator reportCoordinator, string reportKey, string message) {
|
||||||
|
reportCoordinator.Add(reportKey, ReportEntryType.Warning, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new report entry of type error to a report that was previously registered.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="Register()"/>
|
||||||
|
/// <param name="reportKey">Key, i.e. technical name of the report. Should be the same as the one used when registering the report.</param>
|
||||||
|
/// <param name="message">The message to include in the entry.</param>
|
||||||
|
public static void Error(this IReportsCoordinator reportCoordinator, string reportKey, string message) {
|
||||||
|
reportCoordinator.Add(reportKey, ReportEntryType.Error, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
30
src/Orchard/Reports/Services/IReportsCoordinator.cs
Normal file
30
src/Orchard/Reports/Services/IReportsCoordinator.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
namespace Orchard.Reports.Services {
|
||||||
|
/// <summary>
|
||||||
|
/// Exposes a simplified interface for creating reports. Reports provide user-accessible log-like functionality.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <see cref="Orchard.Reports.Services.IReportsManager"/> can be used too to create reports directly.
|
||||||
|
/// </remarks>
|
||||||
|
public interface IReportsCoordinator : IDependency {
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new report entry to a report that was previously registered.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Entries can be only added to a report that was previously registered through Register().
|
||||||
|
/// </remarks>
|
||||||
|
/// <seealso cref="Register()"/>
|
||||||
|
/// <param name="reportKey">Key, i.e. technical name of the report. Should be the same as the one used when registering the report.</param>
|
||||||
|
/// <param name="type">Type of the entry.</param>
|
||||||
|
/// <param name="message">The message to include in the entry.</param>
|
||||||
|
void Add(string reportKey, ReportEntryType type, string message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a new report so entries can be added to it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reportKey">Key, i.e. technical name of the report.</param>
|
||||||
|
/// <param name="activityName">Name of the activity the report is about (e.g. "Upgrade").</param>
|
||||||
|
/// <param name="title">A title better describing what the report is about (e.g. "Migrating routes of Pages, Blog Posts").</param>
|
||||||
|
/// <returns>The report's numerical ID.</returns>
|
||||||
|
int Register(string reportKey, string activityName, string title);
|
||||||
|
}
|
||||||
|
}
|
17
src/Orchard/Reports/Services/IReportsManager.cs
Normal file
17
src/Orchard/Reports/Services/IReportsManager.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Orchard.Reports.Services {
|
||||||
|
/// <summary>
|
||||||
|
/// Service for handling reports. Reports provide user-accessible log-like functionality.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// You can use <see cref="Orchard.Reports.Services.IReportsCoordinator"/> to create reports through a simplified interface.
|
||||||
|
/// </remarks>
|
||||||
|
public interface IReportsManager : ISingletonDependency {
|
||||||
|
void Add(int reportId, ReportEntryType type, string message);
|
||||||
|
int CreateReport(string title, string activityName);
|
||||||
|
Report Get(int reportId);
|
||||||
|
IEnumerable<Report> GetReports();
|
||||||
|
void Flush();
|
||||||
|
}
|
||||||
|
}
|
14
src/Orchard/Reports/Services/IReportsPersister.cs
Normal file
14
src/Orchard/Reports/Services/IReportsPersister.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Orchard.Reports.Services {
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a service that can be used to persist reports.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementations of this interface are commonly used from <see cref="Orchard.Reports.Services.IReportsManager"/> implementations.
|
||||||
|
/// </remarks>
|
||||||
|
public interface IReportsPersister : IDependency {
|
||||||
|
IEnumerable<Report> Fetch();
|
||||||
|
void Save(IEnumerable<Report> reports);
|
||||||
|
}
|
||||||
|
}
|
36
src/Orchard/Reports/Services/ReportsCoordinator.cs
Normal file
36
src/Orchard/Reports/Services/ReportsCoordinator.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Orchard.Logging;
|
||||||
|
|
||||||
|
namespace Orchard.Reports.Services {
|
||||||
|
public class ReportsCoordinator : IReportsCoordinator, IDisposable {
|
||||||
|
private readonly IReportsManager _reportsManager;
|
||||||
|
private readonly IDictionary<string, int> _reports;
|
||||||
|
|
||||||
|
public ReportsCoordinator(IReportsManager reportsManager) {
|
||||||
|
_reportsManager = reportsManager;
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
|
_reports = new Dictionary<string, int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
public void Dispose() {
|
||||||
|
_reportsManager.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string reportKey, ReportEntryType type, string message) {
|
||||||
|
if(!_reports.ContainsKey(reportKey)) {
|
||||||
|
// ignore message if no corresponding report
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_reportsManager.Add(_reports[reportKey], type, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Register(string reportKey, string activityName, string title) {
|
||||||
|
int reportId = _reportsManager.CreateReport(title, activityName);
|
||||||
|
_reports.Add(reportKey, reportId);
|
||||||
|
return reportId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
src/Orchard/Reports/Services/ReportsManager.cs
Normal file
74
src/Orchard/Reports/Services/ReportsManager.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Orchard.Logging;
|
||||||
|
|
||||||
|
namespace Orchard.Reports.Services {
|
||||||
|
public class ReportsManager : IReportsManager {
|
||||||
|
private readonly IReportsPersister _reportsPersister;
|
||||||
|
private List<Report> _reports;
|
||||||
|
private static readonly object _synLock = new object();
|
||||||
|
private bool _isDirty;
|
||||||
|
|
||||||
|
public ReportsManager(IReportsPersister reportsPersister) {
|
||||||
|
_reportsPersister = reportsPersister;
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
|
public void Add(int reportId, ReportEntryType type, string message) {
|
||||||
|
lock ( _synLock ) {
|
||||||
|
LoadReports();
|
||||||
|
_isDirty = true;
|
||||||
|
var report = Get(reportId);
|
||||||
|
if(report == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
report.Entries.Add(new ReportEntry {Message = message, Type = type, Utc = DateTime.UtcNow});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CreateReport(string title, string activityName) {
|
||||||
|
lock ( _synLock ) {
|
||||||
|
LoadReports();
|
||||||
|
_isDirty = true;
|
||||||
|
var reportId = _reports.Count == 0 ? 1 : _reports.Max(r => r.ReportId) + 1;
|
||||||
|
var report = new Report {ActivityName = activityName, ReportId = reportId, Title = title, Utc = DateTime.UtcNow};
|
||||||
|
_reports.Add(report);
|
||||||
|
return reportId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Report Get(int reportId) {
|
||||||
|
lock(_synLock) {
|
||||||
|
LoadReports();
|
||||||
|
return _reports.Where(r => r.ReportId == reportId).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Report> GetReports() {
|
||||||
|
lock ( _synLock ) {
|
||||||
|
LoadReports();
|
||||||
|
return _reports.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Flush() {
|
||||||
|
if ( _reports == null || !_isDirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock ( _synLock ) {
|
||||||
|
_reportsPersister.Save(_reports);
|
||||||
|
_isDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadReports() {
|
||||||
|
if(_reports == null) {
|
||||||
|
_reports = _reportsPersister.Fetch().ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
src/Orchard/Reports/Services/ReportsPersister.cs
Normal file
67
src/Orchard/Reports/Services/ReportsPersister.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Orchard.Environment.Configuration;
|
||||||
|
using Orchard.FileSystems.AppData;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Orchard.Reports.Services {
|
||||||
|
public class ReportsPersister : IReportsPersister {
|
||||||
|
private readonly IAppDataFolder _appDataFolder;
|
||||||
|
private readonly ShellSettings _shellSettings;
|
||||||
|
private readonly string _reportsFileName;
|
||||||
|
private readonly DataContractSerializer _dataContractSerializer;
|
||||||
|
private readonly object _synLock = new object();
|
||||||
|
|
||||||
|
public ReportsPersister(IAppDataFolder appDataFolder, ShellSettings shellSettings) {
|
||||||
|
_appDataFolder = appDataFolder;
|
||||||
|
_shellSettings = shellSettings;
|
||||||
|
_dataContractSerializer = new DataContractSerializer(typeof(Report), new [] { typeof(ReportEntry) });
|
||||||
|
_reportsFileName = Path.Combine(Path.Combine("Sites", _shellSettings.Name), "reports.dat");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Report> Fetch() {
|
||||||
|
lock ( _synLock ) {
|
||||||
|
if ( !_appDataFolder.FileExists(_reportsFileName) ) {
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = _appDataFolder.ReadFile(_reportsFileName);
|
||||||
|
var xmlDocument = XDocument.Parse(text);
|
||||||
|
var rootNode = xmlDocument.Root;
|
||||||
|
if (rootNode == null) {
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var reportNode in rootNode.Elements()) {
|
||||||
|
var reader = new StringReader(reportNode.Value);
|
||||||
|
using (var xmlReader = XmlReader.Create(reader)) {
|
||||||
|
yield return (Report) _dataContractSerializer.ReadObject(xmlReader, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save(IEnumerable<Report> reports) {
|
||||||
|
lock ( _synLock ) {
|
||||||
|
var xmlDocument = new XDocument();
|
||||||
|
xmlDocument.Add(new XElement("Reports"));
|
||||||
|
foreach (var report in reports) {
|
||||||
|
var reportNode = new XElement("Report");
|
||||||
|
var writer = new StringWriter();
|
||||||
|
using (var xmlWriter = XmlWriter.Create(writer)) {
|
||||||
|
_dataContractSerializer.WriteObject(xmlWriter, report);
|
||||||
|
}
|
||||||
|
reportNode.Value = writer.ToString();
|
||||||
|
xmlDocument.Root.Add(reportNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
var saveWriter = new StringWriter();
|
||||||
|
xmlDocument.Save(saveWriter);
|
||||||
|
_appDataFolder.CreateFile(_reportsFileName, saveWriter.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user