Skip to content

Commit 95b0cd8

Browse files
authored
Merge pull request #193 from 1Jesper1/develop
Actually, I'm with the way it is -- I'll merge the PathConfigurations so there is no more duplication. Thanks for your contribution! It's appreciated!
2 parents 4530139 + f2cbe65 commit 95b0cd8

15 files changed

+317
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Papercut
2+
//
3+
// Copyright © 2008 - 2012 Ken Robertson
4+
// Copyright © 2013 - 2020 Jaben Cargman
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
namespace Papercut.Core.Domain.Paths
19+
{
20+
using System;
21+
using System.Collections.Generic;
22+
23+
public interface ILoggingPathConfigurator
24+
{
25+
string DefaultSavePath { get; }
26+
27+
IEnumerable<string> LoadPaths { get; }
28+
29+
event EventHandler RefreshLoadPath;
30+
}
31+
}

src/Papercut.Core/Domain/Paths/IPathTemplatesProvider.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ namespace Papercut.Core.Domain.Paths
2121

2222
public interface IPathTemplatesProvider
2323
{
24-
ObservableCollection<string> PathTemplates { get; }
24+
ObservableCollection<string> MessagePathTemplates { get; }
25+
ObservableCollection<string> LoggingPathTemplates { get; }
2526
}
2627
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// Papercut
2+
//
3+
// Copyright © 2008 - 2012 Ken Robertson
4+
// Copyright © 2013 - 2020 Jaben Cargman
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
namespace Papercut.Core.Domain.Paths
19+
{
20+
using System;
21+
using System.Collections.Generic;
22+
using System.Collections.Specialized;
23+
using System.IO;
24+
using System.Linq;
25+
using System.Text.RegularExpressions;
26+
27+
using Common;
28+
29+
using Papercut.Common.Helper;
30+
31+
using Serilog;
32+
33+
public class LoggingPathConfigurator : ILoggingPathConfigurator
34+
{
35+
static readonly IDictionary<string, string> _templateDictionary;
36+
37+
static readonly Regex TemplateRegex = new Regex(
38+
@"\%(?<name>.+?)\%",
39+
RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Singleline);
40+
41+
readonly ILogger _logger;
42+
43+
readonly IPathTemplatesProvider _pathTemplateProvider;
44+
45+
string _defaultSavePath;
46+
47+
static LoggingPathConfigurator()
48+
{
49+
_templateDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
50+
{
51+
{"BaseDirectory", AppDomain.CurrentDomain.BaseDirectory},
52+
{"DataDirectory", AppConstants.DataDirectory}
53+
};
54+
55+
foreach (
56+
Environment.SpecialFolder specialPath in
57+
EnumHelpers.GetEnumList<Environment.SpecialFolder>())
58+
{
59+
string specialPathName = specialPath.ToString();
60+
61+
if (!_templateDictionary.ContainsKey(specialPathName)) _templateDictionary.Add(specialPathName, Environment.GetFolderPath(specialPath));
62+
}
63+
}
64+
65+
public LoggingPathConfigurator(IPathTemplatesProvider pathTemplateProvider, ILogger logger)
66+
{
67+
if (pathTemplateProvider == null) throw new ArgumentNullException(nameof(pathTemplateProvider));
68+
if (logger == null) throw new ArgumentNullException(nameof(logger));
69+
70+
this._logger = logger;
71+
this._pathTemplateProvider = pathTemplateProvider;
72+
this._pathTemplateProvider.LoggingPathTemplates.CollectionChanged += this.PathTemplatesCollectionChanged;
73+
74+
this.DefaultSavePath = AppDomain.CurrentDomain.BaseDirectory;
75+
this.RenderLoadPaths();
76+
77+
if (this.LoadPaths.Any()) this.DefaultSavePath = this.LoadPaths.First();
78+
79+
this._logger.Information(
80+
"Default Logging Save Path is Set to {DefaultSavePath}",
81+
this.DefaultSavePath);
82+
}
83+
84+
public string DefaultSavePath
85+
{
86+
get
87+
{
88+
if (!Directory.Exists(this._defaultSavePath))
89+
{
90+
this._logger.Information(
91+
"Creating Default Logging Save Path {DefaultSavePath} because it does not exist",
92+
this._defaultSavePath);
93+
94+
Directory.CreateDirectory(this._defaultSavePath);
95+
}
96+
97+
return this._defaultSavePath;
98+
}
99+
private set => this._defaultSavePath = value;
100+
}
101+
102+
public IEnumerable<string> LoadPaths { get; private set; }
103+
104+
public event EventHandler RefreshLoadPath;
105+
106+
void PathTemplatesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
107+
{
108+
this.RenderLoadPaths();
109+
this.OnRefreshLoadPath();
110+
}
111+
112+
void RenderLoadPaths()
113+
{
114+
this.LoadPaths =
115+
this._pathTemplateProvider.LoggingPathTemplates.Select(this.RenderPathTemplate)
116+
.Where(this.ValidatePathExists)
117+
.ToList();
118+
119+
this._logger.Information("Saving logs in the Following Path(s) {@LoadPaths}", this.LoadPaths);
120+
}
121+
122+
protected virtual void OnRefreshLoadPath()
123+
{
124+
EventHandler handler = this.RefreshLoadPath;
125+
handler?.Invoke(this, EventArgs.Empty);
126+
}
127+
128+
string RenderPathTemplate(string pathTemplate)
129+
{
130+
IEnumerable<string> pathKeys =
131+
TemplateRegex.Matches(pathTemplate)
132+
.OfType<Match>()
133+
.Select(s => s.Groups["name"].Value);
134+
string renderedPath = pathTemplate;
135+
136+
foreach (string pathKeyName in pathKeys)
137+
{
138+
string path;
139+
if (_templateDictionary.TryGetValue(pathKeyName, out path))
140+
{
141+
renderedPath =
142+
renderedPath.Replace($"%{pathKeyName}%", path)
143+
.Replace(@"\\", @"\");
144+
}
145+
}
146+
147+
return renderedPath;
148+
}
149+
150+
bool ValidatePathExists(string path)
151+
{
152+
if (path == null) throw new ArgumentNullException(nameof(path));
153+
154+
try
155+
{
156+
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
157+
158+
return true;
159+
}
160+
catch (Exception ex)
161+
{
162+
this._logger.Error(ex, "Failure accessing or creating directory {DirectoryPath}", path);
163+
}
164+
165+
return false;
166+
}
167+
}
168+
}

src/Papercut.Core/Domain/Paths/MessagePathConfigurator.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public MessagePathConfigurator(IPathTemplatesProvider pathTemplateProvider, ILog
6969

7070
this._logger = logger;
7171
this._pathTemplateProvider = pathTemplateProvider;
72-
this._pathTemplateProvider.PathTemplates.CollectionChanged += this.PathTemplatesCollectionChanged;
72+
this._pathTemplateProvider.MessagePathTemplates.CollectionChanged += this.PathTemplatesCollectionChanged;
7373

7474
this.DefaultSavePath = AppDomain.CurrentDomain.BaseDirectory;
7575
this.RenderLoadPaths();
@@ -112,7 +112,7 @@ void PathTemplatesCollectionChanged(object sender, NotifyCollectionChangedEventA
112112
void RenderLoadPaths()
113113
{
114114
this.LoadPaths =
115-
this._pathTemplateProvider.PathTemplates.Select(this.RenderPathTemplate)
115+
this._pathTemplateProvider.MessagePathTemplates.Select(this.RenderPathTemplate)
116116
.Where(this.ValidatePathExists)
117117
.ToList();
118118

src/Papercut.Core/Infrastructure/Container/PapercutCoreModule.cs

+5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ protected override void Load(ContainerBuilder builder)
5151
.AsSelf()
5252
.SingleInstance();
5353

54+
builder.RegisterType<LoggingPathConfigurator>()
55+
.As<ILoggingPathConfigurator>()
56+
.AsSelf()
57+
.SingleInstance();
58+
5459
builder.RegisterType<JsonSettingStore>()
5560
.As<ISettingStore>()
5661
.OnActivated(

src/Papercut.Core/Infrastructure/Logging/RegisterLogger.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace Papercut.Core.Infrastructure.Logging
3131

3232
using Papercut.Common.Domain;
3333
using Papercut.Core.Domain.Application;
34-
34+
using Papercut.Core.Domain.Paths;
3535
using Serilog;
3636
using Serilog.Debugging;
3737

@@ -45,10 +45,10 @@ internal static void Register(ContainerBuilder builder)
4545
builder.Register(c =>
4646
{
4747
var appMeta = c.Resolve<IAppMeta>();
48+
var loggingPathConfigurator = c.Resolve<ILoggingPathConfigurator>();
4849

4950
string logFilePath = Path.Combine(
50-
AppDomain.CurrentDomain.BaseDirectory,
51-
"Logs",
51+
loggingPathConfigurator.DefaultSavePath,
5252
$"{appMeta.AppName}.log");
5353

5454
// support self-logging

src/Papercut.Service/Helpers/PapercutServiceSettings.cs

+6
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ public string MessagePath
4141
set { if (MessagePath != value) Settings.Set("MessagePath", value); }
4242
}
4343

44+
public string LoggingPath
45+
{
46+
get => Settings.GetOrSet<string>("LoggingPath", @"%DataDirectory%\Logs;%BaseDirectory%\Logs", "Base path where logs are written.");
47+
set { if (LoggingPath != value) Settings.Set("LoggingPath", value); }
48+
}
49+
4450
public string SeqEndpoint
4551
{
4652
get => Settings.GetOrSet<string>("SeqEndpoint", @"", "Populate with a endpoint if you want to enable SEQ (https://getseq.net/) logging.");

src/Papercut.Service/Papercut.Service.Settings.json

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
"IPCommUIPort_Description": "## The IP Comm UI listening port (Defaults to 37402).",
2424
"MessagePath": "%DataDirectory%\\Incoming;%BaseDirectory%\\Incoming",
2525
"MessagePath_Description": "## Base path where incoming emails are written.",
26+
"LoggingPath": "%DataDirectory%\\Logs;%BaseDirectory%\\Logs",
27+
"LoggingPath_Description": "## Base path where logs are written.",
2628
"Port": "25",
2729
"Port_Description": "## SMTP Server listening Port. Default is 25.",
2830
"SeqEndpoint": null,

src/Papercut.Service/Program.cs

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ namespace Papercut.Service
2121
using System.Threading.Tasks;
2222

2323
using Autofac;
24-
2524
using Papercut.Core.Infrastructure.Container;
2625
using Papercut.Core.Infrastructure.Logging;
2726
using Papercut.Service.Services;

src/Papercut.Service/Services/ServerPathTemplateProviderService.cs

+10-3
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,20 @@ public class ServerPathTemplateProviderService : IPathTemplatesProvider
2828
{
2929
public ServerPathTemplateProviderService(PapercutServiceSettings serviceSettings)
3030
{
31-
var paths = serviceSettings.MessagePath.Split(';')
31+
var messagePaths = serviceSettings.MessagePath.Split(';')
3232
.Select(s => s.Trim())
3333
.Where(s => !string.IsNullOrWhiteSpace(s));
3434

35-
PathTemplates = new ObservableCollection<string>(paths);
35+
MessagePathTemplates = new ObservableCollection<string>(messagePaths);
36+
37+
var loggingPaths = serviceSettings.LoggingPath.Split(';')
38+
.Select(s => s.Trim())
39+
.Where(s => !string.IsNullOrWhiteSpace(s));
40+
41+
LoggingPathTemplates = new ObservableCollection<string>(loggingPaths);
3642
}
3743

38-
public ObservableCollection<string> PathTemplates { get; private set; }
44+
public ObservableCollection<string> MessagePathTemplates { get; private set; }
45+
public ObservableCollection<string> LoggingPathTemplates { get; private set; }
3946
}
4047
}

src/Papercut.UI/App.config

+3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
<setting name="MessagePaths" serializeAs="String">
5353
<value>%ApplicationData%\Changemaker Studios\Papercut SMTP;%ApplicationData%\Papercut;%BaseDirectory%\Incoming;%DataDirectory%\Incoming</value>
5454
</setting>
55+
<setting name="LoggingPaths" serializeAs="String">
56+
<value>%ApplicationData%\Changemaker Studios\Papercut SMTP;%ApplicationData%\Papercut;%BaseDirectory%\Logs;%DataDirectory%\Logs</value>
57+
</setting>
5558
</Papercut.Properties.Settings>
5659
</userSettings>
5760
<runtime>

src/Papercut.UI/Properties/Settings.Designer.cs

+13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Papercut.UI/Properties/Settings.settings

+3
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,8 @@
4444
<Setting Name="MessagePaths" Type="System.String" Scope="User">
4545
<Value Profile="(Default)">%ApplicationData%\Changemaker Studios\Papercut SMTP;%ApplicationData%\Papercut;%BaseDirectory%\Incoming;%DataDirectory%\Incoming</Value>
4646
</Setting>
47+
<Setting Name="LoggingPaths" Type="System.String" Scope="User">
48+
<Value Profile="(Default)">%ApplicationData%\Changemaker Studios\Papercut SMTP;%ApplicationData%\Papercut;%BaseDirectory%\Logs;%DataDirectory%\Logs</Value>
49+
</Setting>
4750
</Settings>
4851
</SettingsFile>

0 commit comments

Comments
 (0)