Skip to content

Commit

Permalink
This may help with #248 as papercut won't create any directories
Browse files Browse the repository at this point in the history
that don't exist unless it's the DEFAULT directory.
  • Loading branch information
Jaben committed May 11, 2024
1 parent 06d4158 commit 6bf687f
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 74 deletions.
2 changes: 1 addition & 1 deletion src/Papercut.Core/Domain/Paths/IPathConfigurator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface IPathConfigurator
{
string DefaultSavePath { get; }

IEnumerable<string> LoadPaths { get; }
IReadOnlyCollection<string> LoadPaths { get; }

event EventHandler RefreshLoadPath;
}
Expand Down
14 changes: 4 additions & 10 deletions src/Papercut.Core/Domain/Paths/MessagePathConfigurator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,7 @@
// limitations under the License.


namespace Papercut.Core.Domain.Paths
{
public class MessagePathConfigurator : PathConfiguratorBase
{
public MessagePathConfigurator(IPathTemplatesProvider pathTemplateProvider, ILogger logger)
: base(pathTemplateProvider, logger)
{
}
}
}
namespace Papercut.Core.Domain.Paths;

public class MessagePathConfigurator(IPathTemplatesProvider pathTemplateProvider, ILogger logger)
: PathConfiguratorBase(pathTemplateProvider, logger);
21 changes: 21 additions & 0 deletions src/Papercut.Core/Domain/Paths/NoValidSavePathFoundException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Papercut
//
// Copyright © 2008 - 2012 Ken Robertson
// Copyright © 2013 - 2024 Jaben Cargman
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


namespace Papercut.Core.Domain.Paths;

public class NoValidSavePathFoundException(string message) : Exception(message);
169 changes: 107 additions & 62 deletions src/Papercut.Core/Domain/Paths/PathConfiguratorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,100 +18,145 @@

using System.Collections.Specialized;

namespace Papercut.Core.Domain.Paths
namespace Papercut.Core.Domain.Paths;

public abstract class PathConfiguratorBase : IPathConfigurator
{
public abstract class PathConfiguratorBase : IPathConfigurator
readonly ILogger _logger;

readonly IPathTemplatesProvider _pathTemplateProvider;

readonly string _defaultSavePath;

protected PathConfiguratorBase(IPathTemplatesProvider pathTemplateProvider, ILogger logger)
{
readonly ILogger _logger;
if (pathTemplateProvider == null) throw new ArgumentNullException(nameof(pathTemplateProvider));
if (logger == null) throw new ArgumentNullException(nameof(logger));

readonly IPathTemplatesProvider _pathTemplateProvider;
this._logger = logger;
this._pathTemplateProvider = pathTemplateProvider;
this._pathTemplateProvider.MessagePathTemplates.CollectionChanged += this.PathTemplatesCollectionChanged;

string _defaultSavePath;
var paths = this.RenderLoadPaths().ToList();
this.DefaultSavePath = this.GetValidDefaultSavePath(paths);

protected PathConfiguratorBase(IPathTemplatesProvider pathTemplateProvider, ILogger logger)
{
if (pathTemplateProvider == null) throw new ArgumentNullException(nameof(pathTemplateProvider));
if (logger == null) throw new ArgumentNullException(nameof(logger));
this._logger.Information(
"Default Save Path is Set to {DefaultSavePath}",
this.DefaultSavePath);

this._logger = logger;
this._pathTemplateProvider = pathTemplateProvider;
this._pathTemplateProvider.MessagePathTemplates.CollectionChanged += this.PathTemplatesCollectionChanged;
this.LoadPaths = paths.Where(this.PathExists).ToArray();

this.DefaultSavePath = AppDomain.CurrentDomain.BaseDirectory;
this.RenderLoadPaths();
this._logger.Information("Loading from the Following Path(s) {@LoadPaths}", this.LoadPaths);
}

if (this.LoadPaths.Any()) this.DefaultSavePath = this.LoadPaths.First();
public string DefaultSavePath
{
get
{
if (Directory.Exists(this._defaultSavePath)) return this._defaultSavePath;

this._logger.Information(
"Default Save Path is Set to {DefaultSavePath}",
this.DefaultSavePath);
"Creating Default Save Path '{DefaultSavePath}' because it does not exist",
this._defaultSavePath);

Directory.CreateDirectory(this._defaultSavePath);

return this._defaultSavePath;
}
private init => this._defaultSavePath = value;
}

public string DefaultSavePath
{
get
{
if (!Directory.Exists(this._defaultSavePath))
{
this._logger.Information(
"Creating Default Save Path {DefaultSavePath} because it does not exist",
this._defaultSavePath);
public IReadOnlyCollection<string> LoadPaths { get; }

Directory.CreateDirectory(this._defaultSavePath);
}
public event EventHandler RefreshLoadPath;

return this._defaultSavePath;
private string GetValidDefaultSavePath(IEnumerable<string> possiblePaths)
{
foreach (var path in possiblePaths.Append(GetDefaultSavePath()))
{
if (this.IsSavePathIsValid(path))
{
return path;
}
private set => this._defaultSavePath = value;

// no permission -- moving on...
}

public IEnumerable<string> LoadPaths { get; private set; }
throw new NoValidSavePathFoundException("Papercut SMTP does not have access to any paths to save emails!");
}

public event EventHandler RefreshLoadPath;
static string GetDefaultSavePath()
{
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;

void PathTemplatesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
if (baseDirectory.EndsWith("current", StringComparison.OrdinalIgnoreCase))
{
this.RenderLoadPaths();
this.OnRefreshLoadPath();
// Velo installation -- nothing should go in the "current" directory
return Path.GetDirectoryName(baseDirectory)!;
}

void RenderLoadPaths()
{
this.LoadPaths =
this._pathTemplateProvider.MessagePathTemplates.Select(this.RenderPathTemplate)
.Where(this.ValidatePathExists)
.ToList();
return baseDirectory;
}

this._logger.Information("Loading from the Following Path(s) {@LoadPaths}", this.LoadPaths);
}
bool IsSavePathIsValid(string defaultSavePath)
{
if (Directory.Exists(defaultSavePath)) return true;

this._logger.Information(
"Attempting to Create Default Save Path '{DefaultSavePath}' because it does not exist",
defaultSavePath);

protected virtual void OnRefreshLoadPath()
try
{
EventHandler handler = this.RefreshLoadPath;
handler?.Invoke(this, EventArgs.Empty);
}
Directory.CreateDirectory(defaultSavePath);

string RenderPathTemplate(string pathTemplate)
return true;
}
catch (Exception ex)
{
return PathTemplateHelper.RenderPathTemplate(pathTemplate);
this._logger.Error(ex, "Failure accessing path: {DirectoryPath}", defaultSavePath);
}

bool ValidatePathExists(string path)
{
if (path == null) throw new ArgumentNullException(nameof(path));
return false;
}

try
{
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
void PathTemplatesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
this.RenderLoadPaths();
this.OnRefreshLoadPath();
}

return true;
}
catch (Exception ex)
{
this._logger.Error(ex, "Failure accessing or creating directory {DirectoryPath}", path);
}
IEnumerable<string> RenderLoadPaths()
{
return
this._pathTemplateProvider.MessagePathTemplates.Select(this.RenderPathTemplate)
.ToList();
}

return false;
protected virtual void OnRefreshLoadPath()
{
EventHandler handler = this.RefreshLoadPath;
handler?.Invoke(this, EventArgs.Empty);
}

string RenderPathTemplate(string pathTemplate)
{
return PathTemplateHelper.RenderPathTemplate(pathTemplate);
}

bool PathExists(string path)
{
if (path == null) throw new ArgumentNullException(nameof(path));

try
{
return Directory.Exists(path);
}
catch (Exception ex)
{
this._logger.Information(ex, "Excluding search path {DirectoryPath} since there is no access to it", path);
}

return false;
}
}
13 changes: 13 additions & 0 deletions src/Papercut.UI/Papercut.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,17 @@
<ItemGroup>
<Folder Include="Domain\Application\" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="Properties\Settings.settings">
<Generator>PublicSettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion src/Papercut.UI/Properties/Settings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6bf687f

Please sign in to comment.