diff --git a/EasyOC.Modules.sln b/EasyOC.Modules.sln index 55a7920..12a40a9 100644 --- a/EasyOC.Modules.sln +++ b/EasyOC.Modules.sln @@ -32,6 +32,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{2C8B EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyOC.Constants", "src\Shared\EasyOC.Constants\EasyOC.Constants.csproj", "{8C6A4607-9E38-43C3-8738-DDFAE12B9B6B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyOC.CMS.Web", "src\EasyOC.CMS.Web\EasyOC.CMS.Web.csproj", "{6EC107CD-4BA4-4F27-B275-BDFFD2403C55}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyOC.Workflows", "src\Modules\EasyOC.Workflows\EasyOC.Workflows.csproj", "{EB0C3FDC-1125-4194-9FCA-1EE7A1B6FA8B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -58,6 +62,14 @@ Global {8C6A4607-9E38-43C3-8738-DDFAE12B9B6B}.Debug|Any CPU.Build.0 = Debug|Any CPU {8C6A4607-9E38-43C3-8738-DDFAE12B9B6B}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C6A4607-9E38-43C3-8738-DDFAE12B9B6B}.Release|Any CPU.Build.0 = Release|Any CPU + {6EC107CD-4BA4-4F27-B275-BDFFD2403C55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6EC107CD-4BA4-4F27-B275-BDFFD2403C55}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6EC107CD-4BA4-4F27-B275-BDFFD2403C55}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6EC107CD-4BA4-4F27-B275-BDFFD2403C55}.Release|Any CPU.Build.0 = Release|Any CPU + {EB0C3FDC-1125-4194-9FCA-1EE7A1B6FA8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB0C3FDC-1125-4194-9FCA-1EE7A1B6FA8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB0C3FDC-1125-4194-9FCA-1EE7A1B6FA8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB0C3FDC-1125-4194-9FCA-1EE7A1B6FA8B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -68,6 +80,7 @@ Global {9C4736A2-1005-4132-9548-B2E1F3C830E0} = {2C8B39D9-E86E-4BB6-ABAD-22CA1B2EA299} {D4572AB9-35A0-4D0A-B6B7-3A49F26BFF31} = {BBA3C688-E8AD-4177-9817-24D3C097D98A} {8C6A4607-9E38-43C3-8738-DDFAE12B9B6B} = {BBA3C688-E8AD-4177-9817-24D3C097D98A} + {EB0C3FDC-1125-4194-9FCA-1EE7A1B6FA8B} = {2C8B39D9-E86E-4BB6-ABAD-22CA1B2EA299} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {71091DB5-1217-403F-AC42-EB7115ADAB2C} diff --git a/src/EasyOC.CMS.Web/EasyOC.CMS.Web.csproj b/src/EasyOC.CMS.Web/EasyOC.CMS.Web.csproj new file mode 100644 index 0000000..dda7ec2 --- /dev/null +++ b/src/EasyOC.CMS.Web/EasyOC.CMS.Web.csproj @@ -0,0 +1,33 @@ + + + + net6.0 + InProcess + enable + enable + false + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/EasyOC.CMS.Web/Localization/.placeholder b/src/EasyOC.CMS.Web/Localization/.placeholder new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/src/EasyOC.CMS.Web/Localization/.placeholder @@ -0,0 +1 @@ +ÿþ \ No newline at end of file diff --git a/src/EasyOC.CMS.Web/NLog.config b/src/EasyOC.CMS.Web/NLog.config new file mode 100644 index 0000000..2247283 --- /dev/null +++ b/src/EasyOC.CMS.Web/NLog.config @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/EasyOC.CMS.Web/Program.cs b/src/EasyOC.CMS.Web/Program.cs new file mode 100644 index 0000000..861fd96 --- /dev/null +++ b/src/EasyOC.CMS.Web/Program.cs @@ -0,0 +1,30 @@ +using OrchardCore.Logging; + +var builder = WebApplication.CreateBuilder(args); + +builder.Host.UseNLogHost(); + +builder.Services + .AddOrchardCms() + // // Orchard Specific Pipeline + // .ConfigureServices( services => { + // }) + // .Configure( (app, routes, services) => { + // }) +; + +var app = builder.Build(); + +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); + +app.UseOrchardCore(); + +app.Run(); diff --git a/src/EasyOC.CMS.Web/Properties/launchSettings.json b/src/EasyOC.CMS.Web/Properties/launchSettings.json new file mode 100644 index 0000000..63452e8 --- /dev/null +++ b/src/EasyOC.CMS.Web/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:8080", + "sslPort": 44300 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "EasyOC.CMS.Web": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/src/EasyOC.CMS.Web/appsettings.json b/src/EasyOC.CMS.Web/appsettings.json new file mode 100644 index 0000000..6d27889 --- /dev/null +++ b/src/EasyOC.CMS.Web/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, +} diff --git a/src/EasyOC.CMS.Web/wwwroot/.placeholder b/src/EasyOC.CMS.Web/wwwroot/.placeholder new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/src/EasyOC.CMS.Web/wwwroot/.placeholder @@ -0,0 +1 @@ +ÿþ \ No newline at end of file diff --git a/src/Modules/EasyOC.ReplaceAction/ServiceExtensions.cs b/src/Modules/EasyOC.ReplaceAction/ServiceExtensions.cs index 754f62f..bf2342b 100644 --- a/src/Modules/EasyOC.ReplaceAction/ServiceExtensions.cs +++ b/src/Modules/EasyOC.ReplaceAction/ServiceExtensions.cs @@ -2,10 +2,8 @@ using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Linq; using System.Reflection; namespace EasyOC.ReplaceAction @@ -69,6 +67,7 @@ public static IServiceCollection ReplaceActionByActionNames(this IServiceC public static IServiceProvider UseReplaceAction(this IServiceProvider serviceProvider) { var rOptions = serviceProvider.GetRequiredService>(); + var logger = serviceProvider.GetService(); var config = rOptions.Value; var descriptors = serviceProvider.GetRequiredService() @@ -96,9 +95,9 @@ public static IServiceProvider UseReplaceAction(this IServiceProvider servicePro { descriptor.ControllerTypeInfo = item.NewController.GetTypeInfo(); descriptor.MethodInfo = item.ActionMapping[descriptor.ActionName]; - if (logger != null && logger.IsDebugEnabled) + if (logger != null && logger.IsEnabled(LogLevel.Debug)) { - logger.DebugFormat("The Action:{action} of controller:{type} is replaced by {newContorller}.{method}", + logger.LogDebug("The Action:{action} of controller:{type} is replaced by {newContorller}.{method}", item.TargetControllerFullName, descriptor.ActionName, descriptor.ControllerTypeInfo.FullName, diff --git a/src/Modules/EasyOC.Workflows/Constants.cs b/src/Modules/EasyOC.Workflows/Constants.cs new file mode 100644 index 0000000..ddf9146 --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Constants.cs @@ -0,0 +1,7 @@ +namespace EasyOC.Workflows +{ + public class Constants + { + public const string TimersFeautreId = "EasyOC.Workflows.Timers"; + } +} diff --git a/src/Modules/EasyOC.Workflows/EasyOC.Workflows.csproj b/src/Modules/EasyOC.Workflows/EasyOC.Workflows.csproj new file mode 100644 index 0000000..a840ade --- /dev/null +++ b/src/Modules/EasyOC.Workflows/EasyOC.Workflows.csproj @@ -0,0 +1,26 @@ + + + + net6.0 + true + enable + + + + + + + + + + + + + + + + + + + + diff --git a/src/Modules/EasyOC.Workflows/Manifest.cs b/src/Modules/EasyOC.Workflows/Manifest.cs new file mode 100644 index 0000000..3a9b92c --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Manifest.cs @@ -0,0 +1,17 @@ +using OrchardCore.Modules.Manifest; +using static EasyOC.Constants.ManifestConstants; +[assembly: Module( + Author = Author, + Website = Website, + Version = CurrentVersion, + Description = "EasyOC.Workflows", + Category = "Workflows" +)] +[assembly: Feature( + Id = EasyOC.Workflows.Constants.TimersFeautreId, + //Name = "Timer Workflow Activty (Support site time zone)", + Dependencies = new[] { + "OrchardCore.Workflows.Timers" }, + Description = "Make Timer Workflow Activty support site time zone.", + Category = "Workflows" +)] \ No newline at end of file diff --git a/src/Modules/EasyOC.Workflows/Startup.cs b/src/Modules/EasyOC.Workflows/Startup.cs new file mode 100644 index 0000000..5972c42 --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Startup.cs @@ -0,0 +1,33 @@ +using EasyOC.Workflows.Timers; +using Microsoft.Extensions.DependencyInjection; +using OrchardCore.Modules; +using OrchardCore.Workflows.Options; +using OCTimerEvent = OrchardCore.Workflows.Timers.TimerEvent; +namespace EasyOC.Workflows +{ + public class Startup : StartupBase + { + public override void ConfigureServices(IServiceCollection services) + { + + } + + } + [Feature(Constants.TimersFeautreId)] + [RequireFeatures("OrchardCore.Workflows.Timers")] + public class TimerStartup : StartupBase + { + public override void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + if (options.IsActivityRegistered()) + { + options.UnregisterActivityType(); + } + options.RegisterActivity(); + }); + + } + } +} diff --git a/src/Modules/EasyOC.Workflows/Timers/TimerEvent.cs b/src/Modules/EasyOC.Workflows/Timers/TimerEvent.cs new file mode 100644 index 0000000..303054a --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Timers/TimerEvent.cs @@ -0,0 +1,85 @@ +using Microsoft.Extensions.Localization; +using NCrontab; +using OrchardCore.Modules; +using OrchardCore.Settings; +using OrchardCore.Workflows.Abstractions.Models; +using OrchardCore.Workflows.Activities; +using OrchardCore.Workflows.Models; + +namespace EasyOC.Workflows.Timers +{ + public class TimerEvent : EventActivity + { + public static string EventName => nameof(TimerEvent); + private readonly IClock _clock; + private readonly IStringLocalizer S; + private readonly ISiteService _siteService; + + public TimerEvent(IClock clock, IStringLocalizer localizer, ISiteService siteService) + { + _clock = clock; + S = localizer; + _siteService = siteService; + } + + public override string Name => EventName; + + public override LocalizedString DisplayText => S["Timer Event"]; + + public override LocalizedString Category => S["Background"]; + + public string CronExpression + { + get => GetProperty(() => "*/5 * * * *"); + set => SetProperty(value); + } + public bool UseSiteTimeZone + { + get => GetProperty(() => false); + set => SetProperty(value); + } + + private DateTime? StartedTime + { + get => GetProperty(); + set => SetProperty(value); + } + + public override async Task CanExecuteAsync(WorkflowExecutionContext workflowContext, ActivityContext activityContext) + { + return StartedTime == null || await IsExpired(); + } + + public override IEnumerable GetPossibleOutcomes(WorkflowExecutionContext workflowContext, ActivityContext activityContext) + { + return Outcomes(S["Done"]); + } + + public override async Task ResumeAsync(WorkflowExecutionContext workflowContext, ActivityContext activityContext) + { + if (await IsExpired()) + { + workflowContext.LastResult = "TimerEvent"; + return Outcomes("Done"); + } + + return Halt(); + } + + private async Task IsExpired() + { + DateTime when; + var now = _clock.UtcNow; + if (UseSiteTimeZone) + { + var timeZoneId = (await _siteService.GetSiteSettingsAsync()).TimeZoneId; + now = _clock.ConvertToTimeZone(new DateTimeOffset(now), _clock.GetTimeZone(timeZoneId)).DateTime; + } + StartedTime ??= now; + + var schedule = CrontabSchedule.Parse(CronExpression); + when = schedule.GetNextOccurrence(StartedTime.Value); + return now >= when; + } + } +} diff --git a/src/Modules/EasyOC.Workflows/Timers/TimerEventDisplayDriver.cs b/src/Modules/EasyOC.Workflows/Timers/TimerEventDisplayDriver.cs new file mode 100644 index 0000000..aaa18c9 --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Timers/TimerEventDisplayDriver.cs @@ -0,0 +1,20 @@ +using OrchardCore.Workflows.Display; + +namespace EasyOC.Workflows.Timers +{ + public class TimerEventDisplayDriver : ActivityDisplayDriver + { + protected override void EditActivity(TimerEvent source, TimerEventViewModel model) + { + model.CronExpression = source.CronExpression; + model.UseSiteTimeZone = source.UseSiteTimeZone; + + } + + protected override void UpdateActivity(TimerEventViewModel model, TimerEvent target) + { + target.CronExpression = model.CronExpression.Trim(); + target.UseSiteTimeZone = model.UseSiteTimeZone; + } + } +} diff --git a/src/Modules/EasyOC.Workflows/Timers/TimerEventViewModel.cs b/src/Modules/EasyOC.Workflows/Timers/TimerEventViewModel.cs new file mode 100644 index 0000000..fb8196e --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Timers/TimerEventViewModel.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace EasyOC.Workflows.Timers +{ + public class TimerEventViewModel + { + [Required] + public string CronExpression { get; set; } + + public bool UseSiteTimeZone { get; set; } + } +} diff --git a/src/Modules/EasyOC.Workflows/Views/Items/TimerEvent.Fields.Design.cshtml b/src/Modules/EasyOC.Workflows/Views/Items/TimerEvent.Fields.Design.cshtml new file mode 100644 index 0000000..a8abd18 --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Views/Items/TimerEvent.Fields.Design.cshtml @@ -0,0 +1,7 @@ +@using EasyOC.Workflows.Timers +@model ActivityViewModel + +
+

@Model.Activity.GetTitleOrDefault(() => T["Timer"])

+
+@T["{0}", Model.Activity.CronExpression] diff --git a/src/Modules/EasyOC.Workflows/Views/Items/TimerEvent.Fields.Edit.cshtml b/src/Modules/EasyOC.Workflows/Views/Items/TimerEvent.Fields.Edit.cshtml new file mode 100644 index 0000000..3270ba1 --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Views/Items/TimerEvent.Fields.Edit.cshtml @@ -0,0 +1,15 @@ +@model EasyOC.Workflows.Timers.TimerEventViewModel + +
+ + + + @T["The CRON expression."] +
+ +
+
+ + +
+
\ No newline at end of file diff --git a/src/Modules/EasyOC.Workflows/Views/Items/TimerEvent.Fields.Thumbnail.cshtml b/src/Modules/EasyOC.Workflows/Views/Items/TimerEvent.Fields.Thumbnail.cshtml new file mode 100644 index 0000000..0f7c7a6 --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Views/Items/TimerEvent.Fields.Thumbnail.cshtml @@ -0,0 +1,2 @@ +

@T["Timer"]

+

@T["Executes repeatedly according to a specified CRON expression."]

diff --git a/src/Modules/EasyOC.Workflows/Views/_ViewImports.cshtml b/src/Modules/EasyOC.Workflows/Views/_ViewImports.cshtml new file mode 100644 index 0000000..634e2fd --- /dev/null +++ b/src/Modules/EasyOC.Workflows/Views/_ViewImports.cshtml @@ -0,0 +1,16 @@ +@inherits OrchardCore.DisplayManagement.Razor.RazorPage +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@addTagHelper *, OrchardCore.DisplayManagement +@addTagHelper *, OrchardCore.ResourceManagement +@using OrchardCore.Workflows.Deployment; +@using OrchardCore.Workflows.Activities; +@using OrchardCore.Workflows.Helpers; +@using OrchardCore.Workflows.ViewModels; +@using OrchardCore.DisplayManagement.Views; +@using OrchardCore.Mvc.Utilities; +@using Microsoft.Extensions.Localization; +@using Microsoft.AspNetCore.Mvc.Localization; + + + + diff --git a/src/Modules/EasyOC.Workflows/readme.md b/src/Modules/EasyOC.Workflows/readme.md new file mode 100644 index 0000000..c6c3bb5 --- /dev/null +++ b/src/Modules/EasyOC.Workflows/readme.md @@ -0,0 +1,3 @@ +## EasyOC.Workflows.Timers + +Make the `Timer Workflow Activty` support site time zone. \ No newline at end of file