Repo pattern ready for migrations and testing

This commit is contained in:
Fergal Moran
2018-05-11 19:17:06 +01:00
parent 728b07eddc
commit 5f905d3516
24 changed files with 258 additions and 27 deletions

View File

@@ -47,7 +47,7 @@ namespace PodNoms.Api.Controllers {
message.FromUserName = _applicationUser.FullName;
message.FromUserId = _applicationUser.Id;
var chat = _mapper.Map<ChatMessage>(message);
await _chatRepository.AddOrUpdateChat(chat);
await _chatRepository.AddOrUpdateAsync(chat);
await this._unitOfWork.CompleteAsync();
if (await _supportChatService.InitiateSupportRequest(_userId, message)) {

View File

@@ -91,7 +91,7 @@ namespace PodNoms.Api.Controllers {
[HttpGet("all/{podcastSlug}")]
public async Task<IActionResult> GetAllForSlug(string podcastSlug) {
var entries = await _repository.GetAllAsync(podcastSlug);
var entries = await _repository.GetAllForSlugAsync(podcastSlug);
var results = _mapper.Map<List<PodcastEntry>, List<PodcastEntryViewModel>>(entries.ToList());
return Ok(results);

View File

@@ -36,7 +36,7 @@ namespace PodNoms.Api.Controllers {
[HttpGet]
public async Task<IEnumerable<PodcastViewModel>> Get() {
var podcasts = await _repository.GetAllAsync(_applicationUser.Id);
var podcasts = await _repository.GetAllForUserAsync(_applicationUser.Id);
var ret = _mapper.Map<List<Podcast>, List<PodcastViewModel>>(podcasts.ToList());
return ret;
}

View File

@@ -1,8 +1,15 @@
using System;
namespace PodNoms.Api.Models {
public class BaseModel {
public class BaseModel : IEntity {
public int Id { get; set; }
public DateTime CreateDate { get; set; }
public DateTime UpdateDate { get; set; }
}
public interface IEntity {
int Id { get; set; }
DateTime CreateDate { get; set; }
DateTime UpdateDate { get; set; }
}
}

View File

@@ -5,8 +5,7 @@ using Microsoft.Extensions.Options;
using PodNoms.Api.Services.Auth;
namespace PodNoms.Api.Models {
public class ChatMessage : BaseModel {
public int Id { get; set; }
public class ChatMessage : BaseModel, IEntity {
public ApplicationUser FromUser { get; set; }
public ApplicationUser ToUser { get; set; }

View File

@@ -2,7 +2,6 @@ using System.Collections.Generic;
namespace PodNoms.Api.Models {
public class Playlist : BaseModel {
public int Id { get; set; }
//TODO: Update this to use concrete model
public int PodcastId { get; set; }
public string SourceUrl { get; set; }
@@ -14,7 +13,6 @@ namespace PodNoms.Api.Models {
}
}
public class ParsedPlaylistItem : BaseModel {
public int Id { get; set; }
public string VideoId { get; set; }
public string VideoType { get; set; }
public bool IsProcessed { get; set; }

View File

@@ -5,7 +5,6 @@ using PodNoms.Api.Services.Auth;
namespace PodNoms.Api.Models {
public class Podcast : BaseModel {
public int Id { get; set; }
public string Uid { get; set; }
public ApplicationUser AppUser { get; set; }
public string Title { get; set; }

View File

@@ -12,7 +12,6 @@ namespace PodNoms.Api.Models {
}
public class PodcastEntry : BaseModel {
public int Id { get; set; }
public string Uid { get; set; }
public string Author { get; set; }
public string Title { get; set; }

View File

@@ -0,0 +1,58 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
public interface IChatRepository : IRepository<ChatMessage> {
Task<IEnumerable<ChatMessage>> GetSentChats(string fromUserId);
Task<IEnumerable<ChatMessage>> GetReceivedChats(string fromUserId);
Task<IEnumerable<ChatMessage>> GetChats(string fromUserId, string toUserId);
Task<IEnumerable<ChatMessage>> GetAllChats(string userId);
}
public class ChatRepository : GenericRepository<ChatMessage>, IChatRepository {
public ChatRepository(PodNomsDbContext context) : base(context) {
}
public async Task<IEnumerable<ChatMessage>> GetAllChats(string userId) {
var chats = await GetAll()
.Where(c => c.FromUser.Id == userId || c.ToUser.Id == userId)
.Include(c => c.FromUser)
.Include(c => c.ToUser)
.ToListAsync();
return chats;
}
public async Task<IEnumerable<ChatMessage>> GetChats(string fromUserId, string toUserId) {
var chats = await GetAll()
.Where(c => c.FromUser.Id == fromUserId && c.ToUser.Id == toUserId)
.Include(c => c.FromUser)
.Include(c => c.ToUser)
.ToListAsync();
return chats;
}
public async Task<IEnumerable<ChatMessage>> GetReceivedChats(string toUserId) {
var chats = await GetAll()
.Where(c => c.ToUser.Id == toUserId)
.Include(c => c.FromUser)
.Include(c => c.ToUser)
.ToListAsync();
return chats;
}
public async Task<IEnumerable<ChatMessage>> GetSentChats(string fromUserId) {
var chats = await GetAll()
.Where(c => c.FromUser.Id == fromUserId)
.Include(c => c.FromUser)
.Include(c => c.ToUser)
.ToListAsync();
return chats;
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
public interface IEntryRepository : IRepository<PodcastEntry> {
Task<IEnumerable<PodcastEntry>> GetAllForSlugAsync(string podcastSlug);
Task<IEnumerable<PodcastEntry>> GetAllForUserAsync(string userId);
Task<PodcastEntry> GetByUidAsync(string uid);
}
public class EntryRepository : GenericRepository<PodcastEntry>, IEntryRepository {
public EntryRepository(PodNomsDbContext context) : base(context) {
}
public async Task<IEnumerable<PodcastEntry>> GetAllForSlugAsync(string podcastSlug) {
var entries = await GetAll()
.Where(e => e.Podcast.Slug == podcastSlug)
.ToListAsync();
return entries;
}
public async Task<IEnumerable<PodcastEntry>> GetAllForUserAsync(string userId) {
var entries = await GetAll()
.Where(e => e.Podcast.AppUser.Id == userId)
.ToListAsync();
return entries;
}
public async Task<PodcastEntry> GetByUidAsync(string uid) {
var entry = await GetAll()
.SingleOrDefaultAsync(e => e.Uid == uid);
return entry;
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
public interface IRepository<TEntity> where TEntity : class, IEntity {
IQueryable<TEntity> GetAll();
Task<TEntity> GetAsync(int id);
Task<TEntity> CreateAsync(TEntity entity);
Task<TEntity> UpdateAsync(TEntity entity);
Task<TEntity> AddOrUpdateAsync(TEntity entity);
Task DeleteAsync(int id);
}
public abstract class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity {
private PodNomsDbContext _context;
public GenericRepository(PodNomsDbContext context) {
_context = context;
}
public PodNomsDbContext GetContext() {
return _context;
}
public IQueryable<TEntity> GetAll() {
return _context.Set<TEntity>().AsNoTracking();
}
public async Task<TEntity> GetAsync(int id) {
return await _context.Set<TEntity>()
.AsNoTracking()
.FirstOrDefaultAsync(e => e.Id == id);
}
public async Task<TEntity> CreateAsync(TEntity entity) {
var ret = await _context.Set<TEntity>().AddAsync(entity);
await _context.SaveChangesAsync();
return ret as TEntity;
}
public async Task<TEntity> UpdateAsync(TEntity entity) {
var ret = _context.Set<TEntity>().Update(entity);
await _context.SaveChangesAsync();
return ret as TEntity;
}
public async Task<TEntity> AddOrUpdateAsync(TEntity entity) {
var ret = entity;
if (entity.Id != 0) {
// _context.Entry(entry).State = EntityState.Modified
ret = await UpdateAsync(entity);
} else {
ret = await CreateAsync(entity);
}
await _context.SaveChangesAsync();
return ret;
}
public async Task DeleteAsync(int id) {
var entity = await _context.Set<TEntity>().FindAsync(id);
_context.Set<TEntity>().Remove(entity);
}
}
}

View File

@@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
public interface IPlaylistRepository : IRepository<Playlist> {
Task<ParsedPlaylistItem> GetParsedItem(string itemId, int playlistId);
Task<List<ParsedPlaylistItem>> GetUnprocessedItems();
}
public class PlaylistRepository : GenericRepository<Playlist>, IPlaylistRepository {
public PlaylistRepository(PodNomsDbContext context) : base(context) {
}
public async Task<ParsedPlaylistItem> GetParsedItem(string itemId, int playlistId) {
return await GetContext().ParsedPlaylistItems
.Include(i => i.Playlist)
.Include(i => i.Playlist.Podcast)
.Include(i => i.Playlist.Podcast.AppUser)
.SingleOrDefaultAsync(i => i.VideoId == itemId && i.PlaylistId == playlistId);
}
public async Task<List<ParsedPlaylistItem>> GetUnprocessedItems() {
return await GetContext().ParsedPlaylistItems
.Where(p => p.IsProcessed == false)
.Include(i => i.Playlist)
.Include(i => i.Playlist.Podcast)
.Include(i => i.Playlist.Podcast.AppUser)
.ToListAsync();
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
public interface IPodcastRepository : IRepository<Podcast> {
Task<Podcast> GetAsync(string id, string slug);
Task<IEnumerable<Podcast>> GetAllForUserAsync(string userId);
}
public class PodcastRepository : GenericRepository<Podcast>, IPodcastRepository {
public PodcastRepository(PodNomsDbContext context) : base(context) {
}
public async Task<Podcast> GetAsync(string id, string slug) {
var ret = await GetAll()
.Where(p => p.Slug == slug && p.AppUser.Id == id)
.Include(p => p.PodcastEntries)
.Include(p => p.AppUser)
.FirstOrDefaultAsync();
return ret;
}
public async Task<IEnumerable<Podcast>> GetAllForUserAsync(string userId) {
var ret = GetAll()
.Where(u => u.AppUser.Id == userId)
.Include(p => p.AppUser)
.OrderByDescending(p => p.Id);
return await ret.ToListAsync();
}
}
}

View File

@@ -4,7 +4,7 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
namespace PodNoms.Api.Persistence.Old {
public class ChatRepository : IChatRepository {
private readonly PodNomsDbContext _context;

View File

@@ -5,7 +5,7 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
namespace PodNoms.Api.Persistence.Old {
public class EntryRepository : IEntryRepository {
private readonly PodNomsDbContext _context;

View File

@@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
namespace PodNoms.Api.Persistence.Old {
public interface IChatRepository {
Task<IEnumerable<ChatMessage>> GetSentChats(string fromUserId);
Task<IEnumerable<ChatMessage>> GetReceivedChats(string fromUserId);

View File

@@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
namespace PodNoms.Api.Persistence.Old {
public interface IEntryRepository {
Task<PodcastEntry> GetAsync(int id);
Task<PodcastEntry> GetByUidAsync(string uid);

View File

@@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
namespace PodNoms.Api.Persistence.Old {
public interface IPlaylistRepository {
Task<Playlist> GetAsync(int id);
Task<IEnumerable<Playlist>> GetAllAsync();

View File

@@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
namespace PodNoms.Api.Persistence.Old {
public interface IPodcastRepository {
Task<Podcast> GetAsync(int id);
Task<Podcast> GetAsync(string id, string slug);

View File

@@ -4,7 +4,7 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PodNoms.Api.Models;
namespace PodNoms.Api.Persistence {
namespace PodNoms.Api.Persistence.Old {
public class PlaylistRepository : IPlaylistRepository {
private readonly PodNomsDbContext _context;

View File

@@ -6,12 +6,12 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using PodNoms.Api.Models;
using PodNoms.Api.Models.Settings;
using PodNoms.Api.Persistence;
using PodNoms.Api.Persistence.Old;
using PodNoms.Api.Services.Storage;
using PodNoms.Api.Utils;
using PodNoms.Api.Utils.Extensions;
namespace PodNoms.Api.Persistence {
namespace PodNoms.Api.Persistence.Old {
public class PodcastRepository : IPodcastRepository {
private readonly PodNomsDbContext _context;
public IFileUploader _fileUploader { get; }

View File

@@ -55,10 +55,7 @@ namespace PodNoms.Api.Providers {
e => e.UserName,
map => map.MapFrom(vm => vm.Email));
CreateMap<ChatViewModel, ChatMessage>()
.ForMember(
e => e.FromUser,
map => map.MapFrom(vm => e;
CreateMap<ChatViewModel, ChatMessage>();
}
}

View File

@@ -37,7 +37,7 @@ namespace PodNoms.Api.Services.Jobs {
}
public async Task Execute() {
var playlists = await _playlistRepository.GetAllAsync();
var playlists = _playlistRepository.GetAll();
var resultList = new List<ParsedItemResult>();
foreach (var playlist in playlists) {

View File

@@ -61,6 +61,9 @@ namespace PodNoms.Api {
}
public void ConfigureProductionServices(IServiceCollection services) {
services.AddDbContext<PodNomsDbContext>(options => {
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
ConfigureServices(services);
services.AddHangfire(config => {
config.UseSqlServerStorage(Configuration["ConnectionStrings:DefaultConnection"]);
@@ -76,6 +79,11 @@ namespace PodNoms.Api {
});
}
public void ConfigureDevelopmentServices(IServiceCollection services) {
services.AddDbContext<PodNomsDbContext>(options => {
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
options.EnableSensitiveDataLogging(true);
});
ConfigureServices(services);
services.AddHangfire(config => {
config.UseMemoryStorage();
@@ -93,9 +101,6 @@ namespace PodNoms.Api {
public void ConfigureServices(IServiceCollection services) {
Console.WriteLine($"Configuring services: {Configuration.ToString()}");
services.AddDbContext<PodNomsDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddOptions();
services.Configure<AppSettings>(Configuration.GetSection("App"));
services.Configure<StorageSettings>(Configuration.GetSection("Storage"));