Skip to content

Commit

Permalink
refactor (Repository): Move repository methods into RepositoryClass (…
Browse files Browse the repository at this point in the history
…out of Server) (SRP).

- Resolve TaskQueue as singleton.
- (minor) Optimizing usings.
  • Loading branch information
jafin authored and rnwood committed May 11, 2021
1 parent 51b21ea commit 0d300bd
Show file tree
Hide file tree
Showing 23 changed files with 149 additions and 153 deletions.
3 changes: 2 additions & 1 deletion Rnwood.Smtp4dev.Tests/TestMessagesRepository.cs
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Rnwood.Smtp4dev.Data;
using Rnwood.Smtp4dev.DbModel;

namespace Rnwood.Smtp4dev.Tests
Expand All @@ -28,7 +29,7 @@ public Task DeleteMessage(Guid id)
return Task.CompletedTask;
}

public IQueryable<Message> GetMessages()
public IQueryable<Message> GetMessages(bool unTracked = true)
{
return Messages.AsQueryable();
}
Expand Down
91 changes: 42 additions & 49 deletions Rnwood.Smtp4dev/ApiModel/Message.cs
Expand Up @@ -4,13 +4,11 @@
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

namespace Rnwood.Smtp4dev.ApiModel
{
public class Message : ICacheByKey
{

public Message(DbModel.Message dbMessage)
{
Data = dbMessage.Data;
Expand All @@ -23,70 +21,69 @@ public Message(DbModel.Message dbMessage)
Subject = dbMessage.Subject;
SecureConnection = dbMessage.SecureConnection;

Parts = new List<ApiModel.MessageEntitySummary>();
Parts = new List<MessageEntitySummary>(1);
RelayError = dbMessage.RelayError;

if (dbMessage.MimeParseError != null)
{
MimeParseError = dbMessage.MimeParseError;
Headers = new List<Header>();
Parts = new List<MessageEntitySummary>();
Headers = new List<Header>(0);
}
else
{
using (MemoryStream stream = new MemoryStream(dbMessage.Data))
using var stream = new MemoryStream(dbMessage.Data);
MimeMessage = MimeMessage.Load(stream);

if (MimeMessage.From != null)
{
MimeMessage = MimeMessage.Load(stream);
From = MimeMessage.From.ToString();
}

if (MimeMessage.From != null)
{
From = MimeMessage.From.ToString();
}
var recipients = new List<string>(dbMessage.To.Split(",")
.Select(r => r.Trim())
.Where(r => !string.IsNullOrEmpty(r)));

List<string> recipients = new List<string>(dbMessage.To.Split(",")
.Select(r => r.Trim())
.Where(r => !string.IsNullOrEmpty(r)));
if (MimeMessage.To != null)
{
To = string.Join(", ", MimeMessage.To.Select(t => PunyCodeReplacer.DecodePunycode(t.ToString())));

if (MimeMessage.To != null)
foreach (var internetAddress in MimeMessage.To.Where(t => t is MailboxAddress))
{
To = string.Join(", ", MimeMessage.To.Select(t => PunyCodeReplacer.DecodePunycode(t.ToString())));

foreach (MailboxAddress to in MimeMessage.To.Where(t => t is MailboxAddress))
{
recipients.Remove(PunyCodeReplacer.DecodePunycode(to.Address));
}
var to = (MailboxAddress) internetAddress;
recipients.Remove(PunyCodeReplacer.DecodePunycode(to.Address));
}
}

if (MimeMessage.Cc != null)
{
Cc = string.Join(", ", MimeMessage.Cc.Select(t => PunyCodeReplacer.DecodePunycode(t.ToString())));
if (MimeMessage.Cc != null)
{
Cc = string.Join(", ", MimeMessage.Cc.Select(t => PunyCodeReplacer.DecodePunycode(t.ToString())));

foreach (MailboxAddress cc in MimeMessage.Cc.Where(t => t is MailboxAddress))
{
recipients.Remove(PunyCodeReplacer.DecodePunycode(cc.Address));
}
foreach (var internetAddress in MimeMessage.Cc.Where(t => t is MailboxAddress))
{
var cc = (MailboxAddress) internetAddress;
recipients.Remove(PunyCodeReplacer.DecodePunycode(cc.Address));
}
}

Bcc = string.Join(", ", recipients);
Bcc = string.Join(", ", recipients);

Headers = MimeMessage.Headers.Select(h => new Header { Name = h.Field, Value = PunyCodeReplacer.DecodePunycode(h.Value) }).ToList();
Parts.Add(HandleMimeEntity(MimeMessage.Body));
}
Headers = MimeMessage.Headers.Select(h => new Header { Name = h.Field, Value = PunyCodeReplacer.DecodePunycode(h.Value) }).ToList();
Parts.Add(HandleMimeEntity(MimeMessage.Body));
}
}


private MessageEntitySummary HandleMimeEntity(MimeEntity entity)
{
int index = 0;
var index = 0;

return MimeEntityVisitor.VisitWithResults<MessageEntitySummary>(entity, (e, p) =>
{
string fileName = PunyCodeReplacer.DecodePunycode(!string.IsNullOrEmpty(e.ContentDisposition?.FileName)
var fileName = PunyCodeReplacer.DecodePunycode(!string.IsNullOrEmpty(e.ContentDisposition?.FileName)
? e.ContentDisposition?.FileName
: e.ContentType?.Name);
MessageEntitySummary result = new MessageEntitySummary()
var result = new MessageEntitySummary
{
MessageId = Id,
Id = index.ToString(),
Expand Down Expand Up @@ -135,7 +132,7 @@ private MessageEntitySummary HandleMimeEntity(MimeEntity entity)

internal static FileStreamResult GetPartContent(Message result, string cid)
{
MimeEntity contentEntity = GetPart(result, cid);
var contentEntity = GetPart(result, cid);

if (contentEntity is MimePart mimePart)
{
Expand All @@ -146,7 +143,7 @@ internal static FileStreamResult GetPartContent(Message result, string cid)
}
else
{
MemoryStream outputStream = new MemoryStream();
var outputStream = new MemoryStream();
contentEntity.WriteTo(outputStream, true);
outputStream.Seek(0, SeekOrigin.Begin);

Expand All @@ -156,34 +153,30 @@ internal static FileStreamResult GetPartContent(Message result, string cid)

internal static string GetPartContentAsText(Message result, string id)
{
MimeEntity contentEntity = GetPart(result, id);
var contentEntity = GetPart(result, id);

if (contentEntity is MimePart part)
{
using (StreamReader reader = new StreamReader(part.Content.Open()))
{
return reader.ReadToEnd();
}
}
else
{
return contentEntity.ToString();
using var reader = new StreamReader(part.Content.Open());
return reader.ReadToEnd();
}

return contentEntity.ToString();

}



internal static string GetPartSource(Message message, string id)
{
MimeEntity contentEntity = GetPart(message, id);
var contentEntity = GetPart(message, id);
return contentEntity.ToString();
}


private static MimeEntity GetPart(Message message, string id)
{
MessageEntitySummary part = message.Parts.Flatten(p => p.ChildParts).SingleOrDefault(p => p.Id == id);
var part = message.Parts.Flatten(p => p.ChildParts).SingleOrDefault(p => p.Id == id);

if (part == null)
{
Expand All @@ -205,7 +198,7 @@ private static MimeEntity GetPart(Message message, string id)

public string Subject { get; set; }

public List<MessageEntitySummary> Parts { get; set; }
public List<MessageEntitySummary> Parts { get; set; }

public List<Header> Headers { get; set; }

Expand Down
20 changes: 9 additions & 11 deletions Rnwood.Smtp4dev/Controllers/MessagesController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
Expand All @@ -10,13 +11,12 @@
using Microsoft.AspNetCore.Mvc;

using Rnwood.Smtp4dev.ApiModel;
using Rnwood.Smtp4dev.DbModel;
using Rnwood.Smtp4dev.Hubs;
using System.Linq.Dynamic.Core;

using Message = Rnwood.Smtp4dev.DbModel.Message;
using Rnwood.Smtp4dev.Server;
using MimeKit;
using Rnwood.Smtp4dev.Data;

namespace Rnwood.Smtp4dev.Controllers
{
Expand All @@ -31,29 +31,27 @@ public MessagesController(IMessagesRepository messagesRepository, Smtp4devServer
this.server = server;
}

private IMessagesRepository messagesRepository;
private Smtp4devServer server;
private readonly IMessagesRepository messagesRepository;
private readonly Smtp4devServer server;

[HttpGet]

public IEnumerable<ApiModel.MessageSummary> GetSummaries(string sortColumn = "receivedDate", bool sortIsDescending = true)
{
return messagesRepository.GetMessages()
.OrderBy(sortColumn + (sortIsDescending ? " DESC" : ""))
.Select(m => new ApiModel.MessageSummary(m));
.Select(m => new MessageSummary(m));
}

private DbModel.Message GetDbMessage(Guid id)
{
return messagesRepository.GetMessages().SingleOrDefault(m => m.Id == id) ??
throw new FileNotFoundException($"Message with id {id} was not found.");
private Message GetDbMessage(Guid id)
{
return messagesRepository.GetMessages().SingleOrDefault(m => m.Id == id) ?? throw new FileNotFoundException($"Message with id {id} was not found.");
}

[HttpGet("{id}")]
public ApiModel.Message GetMessage(Guid id)
{
var result = new ApiModel.Message(GetDbMessage(id));
return result;
return new ApiModel.Message(GetDbMessage(id));
}

[HttpPost("{id}")]
Expand Down
1 change: 1 addition & 0 deletions Rnwood.Smtp4dev/Controllers/SessionsController.cs
Expand Up @@ -10,6 +10,7 @@
using System.IO;
using MimeKit;
using HtmlAgilityPack;
using Rnwood.Smtp4dev.Data;
using Rnwood.Smtp4dev.Server;

namespace Rnwood.Smtp4dev.Controllers
Expand Down
@@ -1,15 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Rnwood.Smtp4dev
namespace Rnwood.Smtp4dev.Data
{
public interface IMessagesRepository
{
Task MarkMessageRead(Guid id);

IQueryable<DbModel.Message> GetMessages();
IQueryable<DbModel.Message> GetMessages(bool unTracked = true);

Task DeleteMessage(Guid id);

Expand Down
61 changes: 61 additions & 0 deletions Rnwood.Smtp4dev/Data/MessagesRepository.cs
@@ -0,0 +1,61 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Rnwood.Smtp4dev.DbModel;
using Rnwood.Smtp4dev.Hubs;
using Rnwood.Smtp4dev.Server;

namespace Rnwood.Smtp4dev.Data
{
public class MessagesRepository : IMessagesRepository
{
private readonly ITaskQueue taskQueue;
private readonly NotificationsHub notificationsHub;
private readonly Smtp4devDbContext dbContext;

public MessagesRepository(ITaskQueue taskQueue, NotificationsHub notificationsHub, Smtp4devDbContext dbContext)
{
this.taskQueue = taskQueue;
this.notificationsHub = notificationsHub;
this.dbContext = dbContext;
}

public Task MarkMessageRead(Guid id)
{
return taskQueue.QueueTask(() =>
{
var message = dbContext.Messages.FindAsync(id).Result;
if (message?.IsUnread != true) return;
message.IsUnread = false;
dbContext.SaveChanges();
notificationsHub.OnMessagesChanged().Wait();
}, true);
}

public IQueryable<Message> GetMessages(bool unTracked = true)
{
return unTracked ? dbContext.Messages.AsNoTracking() : dbContext.Messages;
}

public Task DeleteMessage(Guid id)
{
return taskQueue.QueueTask(() =>
{
dbContext.Messages.RemoveRange(dbContext.Messages.Where(m => m.Id == id));
dbContext.SaveChanges();
notificationsHub.OnMessagesChanged().Wait();
}, true);
}

public Task DeleteAllMessages()
{
return taskQueue.QueueTask(() =>
{
dbContext.Messages.RemoveRange(dbContext.Messages);
dbContext.SaveChanges();
notificationsHub.OnMessagesChanged().Wait();
}, true);
}
}
}
@@ -1,11 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Rnwood.Smtp4dev.DbModel;

namespace Rnwood.Smtp4dev.DbModel
namespace Rnwood.Smtp4dev.Data
{
public class Smtp4devDbContext : DbContext
{
Expand Down
3 changes: 0 additions & 3 deletions Rnwood.Smtp4dev/DbModel/ImapState.cs
@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace Rnwood.Smtp4dev.DbModel
{
Expand Down
3 changes: 0 additions & 3 deletions Rnwood.Smtp4dev/DbModel/Session.cs
@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Rnwood.SmtpServer;

namespace Rnwood.Smtp4dev.DbModel
Expand Down

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

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

0 comments on commit 0d300bd

Please sign in to comment.