From a41674626968acbee70c62ccc9a590293e71f61f Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 23 Jul 2023 22:57:35 -0700 Subject: [PATCH] DiscordNotificationController.cs got a new route, moved over to ActionResults, records are now tracking the userId and returning common result classes --- .../DiscordNotificationController.cs | 130 ---------- .../v1/DiscordNotificationController.cs | 239 ++++++++++++++++++ .../Repositories/DiscordNotificationTable.cs | 65 ++--- .../Entities/DiscordWebhookEntity.cs | 7 + .../IDiscordNotificationRepository.cs | 20 +- .../Requests/NewDiscordNotificationRequest.cs | 10 + .../DiscordNotificationDetailsResult.cs | 8 + .../Results/DiscordNotificationResult.cs | 8 + 8 files changed, 322 insertions(+), 165 deletions(-) delete mode 100644 Newsbot.Collector.Api/Controllers/DiscordNotificationController.cs create mode 100644 Newsbot.Collector.Api/Controllers/v1/DiscordNotificationController.cs create mode 100644 Newsbot.Collector.Domain/Requests/NewDiscordNotificationRequest.cs create mode 100644 Newsbot.Collector.Domain/Results/DiscordNotificationDetailsResult.cs create mode 100644 Newsbot.Collector.Domain/Results/DiscordNotificationResult.cs diff --git a/Newsbot.Collector.Api/Controllers/DiscordNotificationController.cs b/Newsbot.Collector.Api/Controllers/DiscordNotificationController.cs deleted file mode 100644 index c2c8e55..0000000 --- a/Newsbot.Collector.Api/Controllers/DiscordNotificationController.cs +++ /dev/null @@ -1,130 +0,0 @@ -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Newsbot.Collector.Domain.Dto; -using Newsbot.Collector.Domain.Entities; -using Newsbot.Collector.Domain.Interfaces; - -namespace Newsbot.Collector.Api.Controllers; - -[ApiController] -[Route("api/subscriptions")] -[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] -public class DiscordNotificationController : ControllerBase -{ - private readonly ILogger _logger; - private readonly IDiscordWebHooksRepository _discord; - private readonly ISourcesRepository _sources; - private readonly IDiscordNotificationRepository _discordNotification; - - public DiscordNotificationController(ILogger logger, IDiscordWebHooksRepository discord, ISourcesRepository sources, IDiscordNotificationRepository discordNotification) - { - _logger = logger; - _discord = discord; - _sources = sources; - _discordNotification = discordNotification; - } - - [HttpGet(Name = "ListSubscriptions")] - public IEnumerable List(int page) - { - var res = new List(); - var items = _discordNotification.List(page); - foreach (var item in items) res.Add(DiscordNotificationDto.Convert(item)); - return res; - } - - [HttpGet("{id}")] - public DiscordNotificationDto GetById(Guid id) - { - return DiscordNotificationDto.Convert(_discordNotification.GetById(id)); - } - - [HttpGet("{id}/details")] - public DiscordNotificationDetailsDto GetDetailsById(Guid id) - { - var sub = _discordNotification.GetById(id); - var webhook = _discord.GetById(sub.DiscordWebHookId); - var source = _sources.GetById(sub.SourceId); - - return DiscordNotificationDetailsDto.Convert(sub, source, webhook); - } - - [HttpPost("{id}/delete")] - public void DeleteById(Guid id) - { - _discordNotification.Delete(id); - } - - [HttpGet("by/discordId/{id}")] - public IEnumerable GetByDiscordId(Guid id) - { - var res = new List(); - var items = _discordNotification.ListByWebhook(id); - foreach (var item in items) res.Add(DiscordNotificationDto.Convert(item)); - return res; - } - - [HttpGet("by/sourceId/{id}")] - public IEnumerable GetBySourceId(Guid id) - { - var res = new List(); - var items = _discordNotification.ListBySourceId(id); - foreach (var item in items) res.Add(DiscordNotificationDto.Convert(item)); - return res; - } - - [HttpPost(Name = "New Subscription")] - public ActionResult New(Guid sourceId, Guid discordId) - { - if (sourceId == Guid.Empty) return new BadRequestResult(); - if (discordId == Guid.Empty) return new BadRequestResult(); - - var exists = _discordNotification.GetByWebhookAndSource(discordId, sourceId); - if (exists.Id != Guid.Empty) return DiscordNotificationDto.Convert(exists); - - var discord = _discord.GetById(discordId); - if (discord.Id == Guid.Empty) return new BadRequestResult(); - - var source = _sources.GetById(sourceId); - if (source.Id == Guid.Empty) return new BadRequestResult(); - - var item = _discordNotification.New(new DiscordNotificationEntity - { - Id = Guid.NewGuid(), - SourceId = sourceId, - DiscordWebHookId = discordId, - CodeAllowCommits = false, - CodeAllowReleases = false - }); - - return DiscordNotificationDto.Convert(item); - } - - [HttpPost("new/codeproject")] - public ActionResult NewCodeProjectSubscription(Guid sourceId, Guid discordId, bool allowReleases, - bool allowCommits) - { - if (sourceId == Guid.Empty) return new BadRequestResult(); - if (discordId == Guid.Empty) return new BadRequestResult(); - - var exists = _discordNotification.GetByWebhookAndSource(discordId, sourceId); - if (exists.Id != Guid.Empty) return DiscordNotificationDto.Convert(exists); - - var discord = _discord.GetById(discordId); - if (discord.Id == Guid.Empty) return new BadRequestResult(); - - var source = _sources.GetById(sourceId); - if (source.Id == Guid.Empty) return new BadRequestResult(); - - var sub = _discordNotification.New(new DiscordNotificationEntity - { - DiscordWebHookId = discordId, - SourceId = sourceId, - CodeAllowCommits = allowCommits, - CodeAllowReleases = allowReleases - }); - - return new DiscordNotificationDto(); - } -} \ No newline at end of file diff --git a/Newsbot.Collector.Api/Controllers/v1/DiscordNotificationController.cs b/Newsbot.Collector.Api/Controllers/v1/DiscordNotificationController.cs new file mode 100644 index 0000000..c66951d --- /dev/null +++ b/Newsbot.Collector.Api/Controllers/v1/DiscordNotificationController.cs @@ -0,0 +1,239 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Newsbot.Collector.Api.Middleware; +using Newsbot.Collector.Domain.Dto; +using Newsbot.Collector.Domain.Entities; +using Newsbot.Collector.Domain.Interfaces; +using Newsbot.Collector.Domain.Requests; +using Newsbot.Collector.Domain.Results; + +namespace Newsbot.Collector.Api.Controllers.v1; + +[ApiController] +[Route("api/v1/subscriptions")] +[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] +public class DiscordNotificationController : ControllerBase +{ + private readonly ILogger _logger; + private readonly IDiscordWebHooksRepository _discord; + private readonly ISourcesRepository _sources; + private readonly IDiscordNotificationRepository _discordNotification; + + public DiscordNotificationController(ILogger logger, IDiscordWebHooksRepository discord, ISourcesRepository sources, IDiscordNotificationRepository discordNotification) + { + _logger = logger; + _discord = discord; + _sources = sources; + _discordNotification = discordNotification; + } + + [HttpGet(Name = "ListSubscriptions")] + public ActionResult List(int page) + { + var userId = HttpContext.GetUserId(); + if (userId.Equals(string.Empty)) + { + return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "User Id is missing from the request." } + }); + } + + var res = new List(); + var items = _discordNotification.List(userId, page); + foreach (var item in items) res.Add(DiscordNotificationDto.Convert(item)); + + return new OkObjectResult(new DiscordNotificationResult + { + IsSuccessful = true, + Items = res + }); + } + + [HttpGet("{id}")] + public ActionResult GetById(Guid id) + { + var userId = HttpContext.GetUserId(); + if (userId.Equals(string.Empty)) + { + return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "User Id is missing from the request." } + }); + } + + var res = DiscordNotificationDto.Convert(_discordNotification.GetById(userId, id)); + + return new OkObjectResult(new DiscordNotificationResult + { + IsSuccessful = true, + Items = new List + { + res + } + }); + } + + [HttpGet("{id}/details")] + public ActionResult GetDetailsById(Guid id) + { + var userId = HttpContext.GetUserId(); + if (userId.Equals(string.Empty)) + { + return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "User Id is missing from the request." } + }); + } + + var sub = _discordNotification.GetById(userId, id); + var webhook = _discord.GetById(sub.DiscordWebHookId); + var source = _sources.GetById(sub.SourceId); + + return new OkObjectResult(new DiscordNotificationDetailsResult + { + IsSuccessful = true, + Item = DiscordNotificationDetailsDto.Convert(sub, source, webhook) + }); + } + + [HttpPost("{id}/delete")] + public ActionResult DeleteById(Guid id) + { + var userId = HttpContext.GetUserId(); + if (userId.Equals(string.Empty)) + { + return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "User Id is missing from the request." } + }); + } + + var rowsUpdated = _discordNotification.Delete(userId, id); + if (rowsUpdated == -1) + { + return new OkObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "Record was not own by requested user." } + }); + } + + return new OkObjectResult(new DiscordNotificationResult + { + IsSuccessful = true + }); + } + + [HttpGet("by/discordId/{id}")] + public ActionResult GetByDiscordId(Guid id) + { + var userId = HttpContext.GetUserId(); + if (userId.Equals(string.Empty)) + { + return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "User Id is missing from the request." } + }); + } + + var res = new List(); + var items = _discordNotification.ListByWebhook(userId, id); + foreach (var item in items) res.Add(DiscordNotificationDto.Convert(item)); + + return new OkObjectResult(new DiscordNotificationResult + { + IsSuccessful = true, + Items = res + }); + } + + [HttpGet("by/sourceId/{id}")] + public ActionResult GetBySourceId(Guid id) + { + var userId = HttpContext.GetUserId(); + if (userId.Equals(string.Empty)) + { + return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "User Id is missing from the request." } + }); + } + + var res = new List(); + var items = _discordNotification.ListBySourceId(userId, id); + foreach (var item in items) res.Add(DiscordNotificationDto.Convert(item)); + + return new OkObjectResult(new DiscordNotificationResult + { + IsSuccessful = true, + Items = res + }); + + } + + [HttpPost(Name = "New Subscription")] + public ActionResult New([FromBody] NewDiscordNotificationRequest request) + { + var userId = HttpContext.GetUserId(); + if (userId.Equals(string.Empty)) + { + return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "User Id is missing from the request." } + }); + } + + if (request.SourceId == Guid.Empty) return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "SourceId is missing from the request." } + }); + if (request.DiscordId == Guid.Empty) return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "DiscordId is missing from the request." } + }); + + var exists = _discordNotification.GetByWebhookAndSource(userId, request.DiscordId, request.SourceId); + if (exists.Id != Guid.Empty) return DiscordNotificationDto.Convert(exists); + + var discord = _discord.GetById(request.DiscordId); + if (discord.Id == Guid.Empty) return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "Unable to find the requested DiscordId in the database." } + }); + + var source = _sources.GetById(request.SourceId); + if (source.Id == Guid.Empty) return new BadRequestObjectResult(new DiscordNotificationResult + { + IsSuccessful = false, + ErrorMessage = new List { "Unable to find the requested SourceId in the database." } + }); + + var item = _discordNotification.New(new DiscordNotificationEntity + { + Id = Guid.NewGuid(), + SourceId = request.SourceId, + DiscordWebHookId = request.DiscordId, + CodeAllowCommits = request.AllowCommits, + CodeAllowReleases = request.AllowReleases, + UserId = userId + }); + + return new OkObjectResult(new DiscordNotificationResult + { + IsSuccessful = true, + Items = new List { DiscordNotificationDto.Convert(item) } + }); + } +} \ No newline at end of file diff --git a/Newsbot.Collector.Database/Repositories/DiscordNotificationTable.cs b/Newsbot.Collector.Database/Repositories/DiscordNotificationTable.cs index 9132d8b..4b884a1 100644 --- a/Newsbot.Collector.Database/Repositories/DiscordNotificationTable.cs +++ b/Newsbot.Collector.Database/Repositories/DiscordNotificationTable.cs @@ -1,10 +1,5 @@ -using System.Data; -using Dapper; -using Microsoft.Extensions.Configuration; using Newsbot.Collector.Domain.Entities; using Newsbot.Collector.Domain.Interfaces; -using Newsbot.Collector.Domain.Models; -using Npgsql; namespace Newsbot.Collector.Database.Repositories; @@ -27,66 +22,76 @@ public class DiscordNotificationTable : IDiscordNotificationRepository public DiscordNotificationEntity New(DiscordNotificationEntity model) { model.Id = new Guid(); - //using var context = new DatabaseContext(_connectionString); + _context.DiscordNotification.Add(model); _context.SaveChanges(); + return model; } - public List List(int page = 0, int count = 25) + public List List(string userId, int page = 0, int count = 25) { - //using var context = new DatabaseContext(_connectionString); - return _context.DiscordNotification.Skip(page * count).Take(count).ToList(); + return _context.DiscordNotification + .Where(x => x.UserId != null && x.UserId.Equals(userId)) + .Skip(page * count) + .Take(count) + .ToList(); } + public List ListBySourceId(string userId, Guid id, int page = 0, int count = 25) + { + return _context.DiscordNotification + .Where(f => f.SourceId.Equals(id)) + .Where(f => f.UserId != null && f.UserId.Equals(userId)) + .Skip(page * count) + .ToList(); + } + public List ListBySourceId(Guid id, int page = 0, int count = 25) { - //using var context = new DatabaseContext(_connectionString); - return _context.DiscordNotification.Where(f => f.SourceId.Equals(id)) + return _context.DiscordNotification + .Where(f => f.SourceId.Equals(id)) .Skip(page * count) .ToList(); } - public List ListByWebhook(Guid id, int page = 0, int count = 25) + public List ListByWebhook(string userId, Guid id, int page = 0, int count = 25) { - //using var context = new DatabaseContext(_connectionString); - return _context.DiscordNotification.Where(f => f.DiscordWebHookId.Equals(id)).Skip(page * count).ToList(); + return _context.DiscordNotification + .Where(f => f.DiscordWebHookId.Equals(id)) + .Where(f => f.UserId != null && f.UserId.Equals(userId)) + .Skip(page * count) + .ToList(); } - public DiscordNotificationEntity GetById(Guid id) + public DiscordNotificationEntity GetById(string userId, Guid id) { - //using var context = new DatabaseContext(_connectionString); var res = _context.DiscordNotification + .Where(f => f.UserId != null && f.UserId.Equals(userId)) .FirstOrDefault(f => f.Id.Equals(id)); return res ??= new DiscordNotificationEntity(); } - public DiscordNotificationEntity GetByWebhookAndSource(Guid webhookId, Guid sourceId) + public DiscordNotificationEntity GetByWebhookAndSource(string userId, Guid webhookId, Guid sourceId) { - //using var context = new DatabaseContext(_connectionString); var res = _context.DiscordNotification + .Where(f => f.UserId != null && f.UserId.Equals(userId)) .Where(f => f.DiscordWebHookId.Equals(webhookId)) .FirstOrDefault(f => f.SourceId.Equals(sourceId)); return res ??= new DiscordNotificationEntity(); } - public void Delete(Guid id) + public int Delete(string userId, Guid id) { - //using var context = new DatabaseContext(_connectionString); - var res = _context.DiscordNotification.FirstOrDefault(f => f.Id.Equals(id)); + var res = _context.DiscordNotification + .Where(f => f.UserId != null && f.UserId.Equals(userId)) + .FirstOrDefault(f => f.Id.Equals(id)); if (res is null) { - return; + return -1; } _context.DiscordNotification.Remove(res); - _context.SaveChanges(); + return _context.SaveChanges(); } - - //private IDbConnection OpenConnection(string connectionString) - //{ - // var conn = new NpgsqlConnection(_connectionString); - // conn.Open(); - // return conn; - //} } \ No newline at end of file diff --git a/Newsbot.Collector.Domain/Entities/DiscordWebhookEntity.cs b/Newsbot.Collector.Domain/Entities/DiscordWebhookEntity.cs index 7e7ec40..38758e2 100644 --- a/Newsbot.Collector.Domain/Entities/DiscordWebhookEntity.cs +++ b/Newsbot.Collector.Domain/Entities/DiscordWebhookEntity.cs @@ -1,3 +1,6 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.AspNetCore.Identity; + namespace Newsbot.Collector.Domain.Entities; public class DiscordWebhookEntity @@ -7,4 +10,8 @@ public class DiscordWebhookEntity public string Server { get; set; } = ""; public string Channel { get; set; } = ""; public bool Enabled { get; set; } + + public string? UserId { get; set; } + [ForeignKey(nameof(UserId))] + public IdentityUser? User { get; set; } } \ No newline at end of file diff --git a/Newsbot.Collector.Domain/Interfaces/IDiscordNotificationRepository.cs b/Newsbot.Collector.Domain/Interfaces/IDiscordNotificationRepository.cs index c71e137..f2dbf61 100644 --- a/Newsbot.Collector.Domain/Interfaces/IDiscordNotificationRepository.cs +++ b/Newsbot.Collector.Domain/Interfaces/IDiscordNotificationRepository.cs @@ -7,12 +7,22 @@ public interface IDiscordNotificationRepository { DiscordNotificationEntity New(DiscordNotificationEntity model); - List List(int page = 0, int count = 25); + List List(string userId, int page = 0, int count = 25); + List ListBySourceId(string userId, Guid id, int page = 0, int count = 25); + + /// + /// This will collect all the records based on the SourceId. + /// Background jobs can use this but user facing calls need to define UserId + /// + /// + /// + /// + /// List ListBySourceId(Guid id, int page = 0, int count = 25); - List ListByWebhook(Guid id, int page = 0, int count = 25); + List ListByWebhook(string userId, Guid id, int page = 0, int count = 25); - DiscordNotificationEntity GetById(Guid id); - DiscordNotificationEntity GetByWebhookAndSource(Guid webhookId, Guid sourceId); + DiscordNotificationEntity GetById(string userId, Guid id); + DiscordNotificationEntity GetByWebhookAndSource(string userId, Guid webhookId, Guid sourceId); - void Delete(Guid id); + int Delete(string userId, Guid id); } \ No newline at end of file diff --git a/Newsbot.Collector.Domain/Requests/NewDiscordNotificationRequest.cs b/Newsbot.Collector.Domain/Requests/NewDiscordNotificationRequest.cs new file mode 100644 index 0000000..0ba7f4d --- /dev/null +++ b/Newsbot.Collector.Domain/Requests/NewDiscordNotificationRequest.cs @@ -0,0 +1,10 @@ +namespace Newsbot.Collector.Domain.Requests; + +public class NewDiscordNotificationRequest +{ + public Guid SourceId { get; set; } + public Guid DiscordId { get; set; } + + public bool AllowReleases { get; set; } = false; + public bool AllowCommits { get; set; } = false; +} \ No newline at end of file diff --git a/Newsbot.Collector.Domain/Results/DiscordNotificationDetailsResult.cs b/Newsbot.Collector.Domain/Results/DiscordNotificationDetailsResult.cs new file mode 100644 index 0000000..0d8d40f --- /dev/null +++ b/Newsbot.Collector.Domain/Results/DiscordNotificationDetailsResult.cs @@ -0,0 +1,8 @@ +using Newsbot.Collector.Domain.Dto; + +namespace Newsbot.Collector.Domain.Results; + +public class DiscordNotificationDetailsResult : BaseResult +{ + public DiscordNotificationDetailsDto? Item { get; set; } +} \ No newline at end of file diff --git a/Newsbot.Collector.Domain/Results/DiscordNotificationResult.cs b/Newsbot.Collector.Domain/Results/DiscordNotificationResult.cs new file mode 100644 index 0000000..9cb27da --- /dev/null +++ b/Newsbot.Collector.Domain/Results/DiscordNotificationResult.cs @@ -0,0 +1,8 @@ +using Newsbot.Collector.Domain.Dto; + +namespace Newsbot.Collector.Domain.Results; + +public class DiscordNotificationResult : BaseResult +{ + public IEnumerable? Items { get; set; } +} \ No newline at end of file