Merge pull request 'Migration to EF and starting to add Identity' (#11) from features/ef-identity-migration into main

Reviewed-on: #11
This commit is contained in:
jtom38 2023-07-09 22:18:59 -07:00
commit 42258ec56f
56 changed files with 3103 additions and 475 deletions

View File

@ -0,0 +1,89 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Newsbot.Collector.Api.Domain.Requests;
using Newsbot.Collector.Api.Domain.Response;
using Newsbot.Collector.Api.Services;
using Newsbot.Collector.Domain.Dto;
using Newsbot.Collector.Domain.Entities;
namespace Newsbot.Collector.Api.Controllers;
[ApiController]
[Route("/api/account")]
public class AccountController : ControllerBase
{
private IIdentityService _identityService;
public AccountController(IIdentityService identityService)
{
_identityService = identityService;
}
[HttpPost("register")]
public IActionResult Register([FromBody] RegisterUserRequest user)
{
if (!ModelState.IsValid)
{
return new BadRequestObjectResult(new AuthFailedResponse
{
Errors = ModelState.Values
.Select(x => x.Errors
.Select(y => y.ErrorMessage).FirstOrDefault())
});
}
if (user.Email is null)
{
return new BadRequestResult();
}
if (user.Password is null)
{
return new BadRequestResult();
}
var response = _identityService.Register(user.Email, user.Password);
if (!response.IsSuccessful)
{
return new BadRequestObjectResult( new AuthFailedResponse
{
Errors = response.ErrorMessage
});
}
return new OkObjectResult(new AuthSuccessfulResponse
{
Token = response.Token
});
}
[HttpPost("login")]
public IActionResult Login([FromBody] UserLoginRequest request)
{
if (request.Email is null)
{
return new BadRequestResult();
}
if (request.Password is null)
{
return new BadRequestResult();
}
var response = _identityService.Login(request.Email, request.Password);
if (!response.IsSuccessful)
{
return new BadRequestObjectResult( new AuthFailedResponse
{
Errors = response.ErrorMessage
});
}
return new OkObjectResult(new AuthSuccessfulResponse
{
Token = response.Token
});
}
}

View File

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newsbot.Collector.Database.Repositories;
using Newsbot.Collector.Domain.Dto; using Newsbot.Collector.Domain.Dto;
using Newsbot.Collector.Domain.Interfaces; using Newsbot.Collector.Domain.Interfaces;
using Newsbot.Collector.Domain.Models; using Newsbot.Collector.Domain.Models;
@ -9,17 +10,18 @@ namespace Newsbot.Collector.Api.Controllers;
[ApiController] [ApiController]
[Route("api/articles")] [Route("api/articles")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class ArticlesController : ControllerBase public class ArticlesController : ControllerBase
{ {
private readonly IArticlesRepository _articles;
private readonly ILogger<ArticlesController> _logger; private readonly ILogger<ArticlesController> _logger;
private readonly IArticlesRepository _articles;
private readonly ISourcesRepository _sources; private readonly ISourcesRepository _sources;
public ArticlesController(ILogger<ArticlesController> logger, IOptions<ConnectionStrings> settings) public ArticlesController(ILogger<ArticlesController> logger, IArticlesRepository articles, ISourcesRepository sources)
{ {
_logger = logger; _logger = logger;
_articles = new ArticlesTable(settings.Value.Database); _articles = articles;
_sources = new SourcesTable(settings.Value.Database); _sources = sources;
} }
[HttpGet(Name = "GetArticles")] [HttpGet(Name = "GetArticles")]

View File

@ -1,4 +1,6 @@
using Hangfire; using Hangfire;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newsbot.Collector.Domain.Models.Config; using Newsbot.Collector.Domain.Models.Config;
@ -8,6 +10,7 @@ namespace Newsbot.Collector.Api.Controllers;
[ApiController] [ApiController]
[Route("api/codeprojects")] [Route("api/codeprojects")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class CodeProjectController public class CodeProjectController
{ {
private readonly ConfigSectionConnectionStrings _connectionStrings; private readonly ConfigSectionConnectionStrings _connectionStrings;

View File

@ -0,0 +1,130 @@
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<DiscordNotificationController> _logger;
private readonly IDiscordWebHooksRepository _discord;
private readonly ISourcesRepository _sources;
private readonly IDiscordNotificationRepository _discordNotification;
public DiscordNotificationController(ILogger<DiscordNotificationController> logger, IDiscordWebHooksRepository discord, ISourcesRepository sources, IDiscordNotificationRepository discordNotification)
{
_logger = logger;
_discord = discord;
_sources = sources;
_discordNotification = discordNotification;
}
[HttpGet(Name = "ListSubscriptions")]
public IEnumerable<DiscordNotificationDto> List(int page)
{
var res = new List<DiscordNotificationDto>();
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<DiscordNotificationDto> GetByDiscordId(Guid id)
{
var res = new List<DiscordNotificationDto>();
var items = _discordNotification.ListByWebhook(id);
foreach (var item in items) res.Add(DiscordNotificationDto.Convert(item));
return res;
}
[HttpGet("by/sourceId/{id}")]
public IEnumerable<DiscordNotificationDto> GetBySourceId(Guid id)
{
var res = new List<DiscordNotificationDto>();
var items = _discordNotification.ListBySourceId(id);
foreach (var item in items) res.Add(DiscordNotificationDto.Convert(item));
return res;
}
[HttpPost(Name = "New Subscription")]
public ActionResult<DiscordNotificationDto> 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<DiscordNotificationDto> 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();
}
}

View File

@ -1,4 +1,6 @@
using System.Net; using System.Net;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newsbot.Collector.Database.Repositories; using Newsbot.Collector.Database.Repositories;
@ -11,17 +13,16 @@ namespace Newsbot.Collector.Api.Controllers;
[ApiController] [ApiController]
[Route("api/discord/webhooks")] [Route("api/discord/webhooks")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class DiscordWebHookController : ControllerBase public class DiscordWebHookController : ControllerBase
{ {
private readonly ILogger<DiscordWebHookController> _logger; private readonly ILogger<DiscordWebHookController> _logger;
private readonly ConnectionStrings _settings;
private readonly IDiscordWebHooksRepository _webhooks; private readonly IDiscordWebHooksRepository _webhooks;
public DiscordWebHookController(ILogger<DiscordWebHookController> logger, IOptions<ConnectionStrings> settings) public DiscordWebHookController(ILogger<DiscordWebHookController> logger, IOptions<ConnectionStrings> settings, IDiscordWebHooksRepository webhooks)
{ {
_logger = logger; _logger = logger;
_settings = settings.Value; _webhooks = webhooks;
_webhooks = new DiscordWebhooksTable(_settings.Database);
} }
[HttpGet(Name = "GetDiscordWebhooks")] [HttpGet(Name = "GetDiscordWebhooks")]

View File

@ -1,13 +1,17 @@
using Hangfire; using Hangfire;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newsbot.Collector.Domain.Models.Config; using Newsbot.Collector.Domain.Models.Config;
using Newsbot.Collector.Domain.Models.Config.Sources;
using Newsbot.Collector.Services.Jobs; using Newsbot.Collector.Services.Jobs;
namespace Newsbot.Collector.Api.Controllers; namespace Newsbot.Collector.Api.Controllers;
[ApiController] [ApiController]
[Route("api/rss")] [Route("api/rss")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class RssController public class RssController
{ {
private readonly ConfigSectionConnectionStrings _connectionStrings; private readonly ConfigSectionConnectionStrings _connectionStrings;

View File

@ -1,3 +1,5 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newsbot.Collector.Database.Repositories; using Newsbot.Collector.Database.Repositories;
@ -12,22 +14,18 @@ namespace Newsbot.Collector.Api.Controllers;
[ApiController] [ApiController]
[Route("api/sources")] [Route("api/sources")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class SourcesController : ControllerBase public class SourcesController : ControllerBase
{ {
private readonly IArticlesRepository _articles;
//private readonly ConnectionStrings _settings;
private readonly IIconsRepository _icons;
private readonly ILogger<SourcesController> _logger; private readonly ILogger<SourcesController> _logger;
private readonly IIconsRepository _icons;
private readonly ISourcesRepository _sources; private readonly ISourcesRepository _sources;
public SourcesController(ILogger<SourcesController> logger, IOptions<ConnectionStrings> settings) public SourcesController(ILogger<SourcesController> logger, IIconsRepository icons, ISourcesRepository sources)
{ {
_logger = logger; _logger = logger;
//_settings = settings.Value; _icons = icons;
_sources = new SourcesTable(settings.Value.Database); _sources = sources;
_icons = new IconsTable(settings.Value.Database);
_articles = new ArticlesTable(settings.Value.Database);
} }
[HttpGet(Name = "GetSources")] [HttpGet(Name = "GetSources")]

View File

@ -1,130 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newsbot.Collector.Database.Repositories;
using Newsbot.Collector.Domain.Dto;
using Newsbot.Collector.Domain.Entities;
using Newsbot.Collector.Domain.Interfaces;
using Newsbot.Collector.Domain.Models;
namespace Newsbot.Collector.Api.Controllers;
[ApiController]
[Route("api/subscriptions")]
public class SubscriptionsController : ControllerBase
{
private readonly IDiscordWebHooksRepository _discord;
private readonly ILogger<SubscriptionsController> _logger;
private readonly ISourcesRepository _sources;
private readonly ISubscriptionRepository _subscription;
public SubscriptionsController(ILogger<SubscriptionsController> logger, IOptions<ConnectionStrings> settings)
{
_logger = logger;
_subscription = new SubscriptionsTable(settings.Value.Database);
_discord = new DiscordWebhooksTable(settings.Value.Database);
_sources = new SourcesTable(settings.Value.Database);
}
[HttpGet(Name = "ListSubscriptions")]
public IEnumerable<SubscriptionDto> List(int page)
{
var res = new List<SubscriptionDto>();
var items = _subscription.List(page);
foreach (var item in items) res.Add(SubscriptionDto.Convert(item));
return res;
}
[HttpGet("{id}")]
public SubscriptionDto GetById(Guid id)
{
return SubscriptionDto.Convert(_subscription.GetById(id));
}
[HttpGet("{id}/details")]
public SubscriptionDetailsDto GetDetailsById(Guid id)
{
var sub = _subscription.GetById(id);
var webhook = _discord.GetById(sub.DiscordWebHookId);
var source = _sources.GetById(sub.SourceId);
return SubscriptionDetailsDto.Convert(sub, source, webhook);
}
[HttpPost("{id}/delete")]
public void DeleteById(Guid id)
{
_subscription.Delete(id);
}
[HttpGet("by/discordid/{id}")]
public IEnumerable<SubscriptionDto> GetByDiscordId(Guid id)
{
var res = new List<SubscriptionDto>();
var items = _subscription.ListByWebhook(id);
foreach (var item in items) res.Add(SubscriptionDto.Convert(item));
return res;
}
[HttpGet("by/sourceId/{id}")]
public IEnumerable<SubscriptionDto> GetBySourceId(Guid id)
{
var res = new List<SubscriptionDto>();
var items = _subscription.ListBySourceId(id);
foreach (var item in items) res.Add(SubscriptionDto.Convert(item));
return res;
}
[HttpPost(Name = "New Subscription")]
public ActionResult<SubscriptionDto> New(Guid sourceId, Guid discordId)
{
if (sourceId == Guid.Empty) return new BadRequestResult();
if (discordId == Guid.Empty) return new BadRequestResult();
var exists = _subscription.GetByWebhookAndSource(discordId, sourceId);
if (exists.Id != Guid.Empty) return SubscriptionDto.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 = _subscription.New(new SubscriptionEntity
{
Id = Guid.NewGuid(),
SourceId = sourceId,
DiscordWebHookId = discordId,
CodeAllowCommits = false,
CodeAllowReleases = false
});
return SubscriptionDto.Convert(item);
}
[HttpPost("new/codeproject")]
public ActionResult<SubscriptionDto> 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 = _subscription.GetByWebhookAndSource(discordId, sourceId);
if (exists.Id != Guid.Empty) return SubscriptionDto.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 = _subscription.New(new SubscriptionEntity
{
DiscordWebHookId = discordId,
SourceId = sourceId,
CodeAllowCommits = allowCommits,
CodeAllowReleases = allowReleases
});
return new SubscriptionDto();
}
}

View File

@ -1,7 +1,10 @@
using Hangfire; using Hangfire;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newsbot.Collector.Domain.Models.Config; using Newsbot.Collector.Domain.Models.Config;
using Newsbot.Collector.Domain.Models.Config.Sources;
using Newsbot.Collector.Services.Jobs; using Newsbot.Collector.Services.Jobs;
using ILogger = Grpc.Core.Logging.ILogger; using ILogger = Grpc.Core.Logging.ILogger;
@ -9,6 +12,7 @@ namespace Newsbot.Collector.Api.Controllers;
[ApiController] [ApiController]
[Route("api/youtube")] [Route("api/youtube")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class YoutubeController public class YoutubeController
{ {
private readonly ILogger<YoutubeController> _logger; private readonly ILogger<YoutubeController> _logger;

View File

@ -0,0 +1,45 @@
using Microsoft.AspNetCore.Mvc;
using Newsbot.Collector.Api.Authentication;
using Newsbot.Collector.Domain.Entities;
using Newsbot.Collector.Domain.Interfaces;
namespace Newsbot.Collector.Api.Controllers;
[ApiController]
[Route("api/v1/user")]
public class UserController : Controller
{
private ILogger<UserController> _logger;
private IUserSourceSubscription _subscription;
public UserController(ILogger<UserController> logger, IUserSourceSubscription subscription)
{
_logger = logger;
_subscription = subscription;
}
[HttpPost("listSubscriptions")]
public ActionResult ListSubscriptions()
{
_logger.LogInformation("'/api/v1/user/listSubscriptions' was requested");
var userId = HttpContext.GetUserId();
if (userId.Equals(string.Empty))
{
_logger.LogWarning("Unable to find the user ID in the JWD Token");
return new BadRequestResult();
}
try
{
var results = _subscription.ListUserSubscriptions(Guid.Parse(userId));
return new OkObjectResult(results);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to pull subscriptions for userId \'{UserId}\'", userId);
return new NoContentResult();
}
}
}

View File

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
namespace Newsbot.Collector.Api.Domain.Requests;
public class RegisterUserRequest
{
//public string? Name { get; set; }
[EmailAddress]
public string? Email { get; set; }
public string? Password { get; set; }
}

View File

@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations;
namespace Newsbot.Collector.Api.Domain.Requests;
public class UserLoginRequest
{
[EmailAddress]
public string? Email { get; set; }
public string? Password { get; set; }
}

View File

@ -0,0 +1,6 @@
namespace Newsbot.Collector.Api.Domain.Response;
public class AuthFailedResponse
{
public IEnumerable<string?>? Errors { get; set; }
}

View File

@ -0,0 +1,8 @@
namespace Newsbot.Collector.Api.Domain.Response;
public class AuthSuccessfulResponse
{
// might want to validate the user before we return the token
public string? Token { get; set; }
}

View File

@ -0,0 +1,11 @@
using System.Collections;
namespace Newsbot.Collector.Api.Domain.Results;
public class AuthenticationResult
{
public string? Token { get; set; }
public bool IsSuccessful { get; set; }
public IEnumerable<string>? ErrorMessage { get; set; }
}

View File

@ -0,0 +1,14 @@
namespace Newsbot.Collector.Api.Authentication;
public static class JwtUserIdExtension
{
public static string GetUserId(this HttpContext context)
{
if (context.User == null)
{
return string.Empty;
}
return context.User.Claims.Single(x => x.Type == "id").Value;
}
}

View File

@ -13,6 +13,7 @@
<PackageReference Include="AspNetCore.HealthChecks.UI.Core" Version="6.0.5" /> <PackageReference Include="AspNetCore.HealthChecks.UI.Core" Version="6.0.5" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.33" /> <PackageReference Include="Hangfire.AspNetCore" Version="1.7.33" />
<PackageReference Include="Hangfire.MemoryStorage" Version="1.7.0" /> <PackageReference Include="Hangfire.MemoryStorage" Version="1.7.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.8" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.0" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.8"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.8">

View File

@ -1,14 +1,24 @@
using System.Text;
using Hangfire; using Hangfire;
using Hangfire.MemoryStorage; using Hangfire.MemoryStorage;
using HealthChecks.UI.Client; using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Newsbot.Collector.Api; using Newsbot.Collector.Api;
using Newsbot.Collector.Api.Authentication; using Newsbot.Collector.Api.Authentication;
using Newsbot.Collector.Api.Services;
using Newsbot.Collector.Database; using Newsbot.Collector.Database;
using Newsbot.Collector.Database.Repositories;
using Newsbot.Collector.Domain.Consts; using Newsbot.Collector.Domain.Consts;
using Newsbot.Collector.Domain.Entities;
using Newsbot.Collector.Domain.Interfaces;
using Newsbot.Collector.Domain.Models; using Newsbot.Collector.Domain.Models;
using Newsbot.Collector.Domain.Models.Config; using Newsbot.Collector.Domain.Models.Config;
using Newsbot.Collector.Domain.Models.Config.Sources;
using Serilog; using Serilog;
using Serilog.Events; using Serilog.Events;
using ILogger = Serilog.ILogger; using ILogger = Serilog.ILogger;
@ -23,30 +33,77 @@ var config = GetConfiguration();
builder.Configuration.AddConfiguration(config); builder.Configuration.AddConfiguration(config);
Log.Logger = GetLogger(config); Log.Logger = GetLogger(config);
Log.Information("Starting up"); Log.Information("Starting up");
// configure Entity Framework
var dbconn = config.GetConnectionString("Database");
builder.Services.AddDbContext<DatabaseContext>(o => o.UseNpgsql(dbconn ?? ""));
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<DatabaseContext>();
builder.Services.AddScoped<IArticlesRepository, ArticlesTable>();
builder.Services.AddScoped<IDiscordQueueRepository, DiscordQueueTable>();
builder.Services.AddScoped<IDiscordWebHooksRepository, DiscordWebhooksTable>();
builder.Services.AddScoped<IIconsRepository, IconsTable>();
builder.Services.AddScoped<ISourcesRepository, SourcesTable>();
builder.Services.AddScoped<IDiscordNotificationRepository, DiscordNotificationTable>();
builder.Services.AddScoped<IUserSourceSubscription, UserSourceSubscriptionTable>();
// Configure Identity
builder.Services.AddScoped<IIdentityService, IdentityService>();
// Configure Hangfire // Configure Hangfire
builder.Services.AddHangfire(f => f.UseMemoryStorage()); builder.Services.AddHangfire(f => f.UseMemoryStorage());
builder.Services.AddHangfireServer(); builder.Services.AddHangfireServer();
GlobalConfiguration.Configuration.UseSerilogLogProvider(); GlobalConfiguration.Configuration.UseSerilogLogProvider();
// Add Health Checks
builder.Services.AddHealthChecks() builder.Services.AddHealthChecks()
.AddNpgSql(config.GetValue<string>(ConfigConnectionStringConst.Database) ?? ""); .AddNpgSql(config.GetValue<string>(ConfigConnectionStringConst.Database) ?? "");
builder.Services.AddControllers(); builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen();
builder.Services.Configure<ConnectionStrings>(config.GetSection("ConnectionStrings")); builder.Services.Configure<ConnectionStrings>(config.GetSection("ConnectionStrings"));
builder.Services.Configure<ConfigSectionConnectionStrings>(config.GetSection(ConfigSectionsConst.ConnectionStrings)); builder.Services.Configure<ConfigSectionConnectionStrings>(config.GetSection(ConfigSectionsConst.ConnectionStrings));
builder.Services.Configure<ConfigSectionRssModel>(config.GetSection(ConfigSectionsConst.Rss)); builder.Services.Configure<ConfigSectionRssModel>(config.GetSection(ConfigSectionsConst.Rss));
builder.Services.Configure<ConfigSectionYoutubeModel>(config.GetSection(ConfigSectionsConst.Youtube)); builder.Services.Configure<ConfigSectionYoutubeModel>(config.GetSection(ConfigSectionsConst.Youtube));
//builder.Services.Configure< //builder.Services.Configure<
// Configure JWT for auth
var jwtSettings = new JwtSettings();
config.Bind(nameof(jwtSettings), jwtSettings);
builder.Services.AddSingleton(jwtSettings);
builder.Services.AddAuthentication(x =>
{
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtSettings.Secret ?? "")),
ValidateIssuer = false,
ValidateAudience = false,
RequireExpirationTime = false,
ValidateLifetime = true
};
});
builder.Services.AddSwaggerGen(cfg => builder.Services.AddSwaggerGen(cfg =>
{ {
cfg.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme cfg.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme
{ {
Description = "The API key to access the API", Description = "The API key to access the API",
@ -56,23 +113,45 @@ builder.Services.AddSwaggerGen(cfg =>
Scheme = "ApiKeyScheme" Scheme = "ApiKeyScheme"
}); });
var scheme = new OpenApiSecurityScheme cfg.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{ {
Reference = new OpenApiReference Description = "JWT Authorization Header using the bearer scheme",
{ Name = "Authorization",
Type = ReferenceType.SecurityScheme, In = ParameterLocation.Header,
Id = "ApiKey" Type = SecuritySchemeType.ApiKey
}, });
In = ParameterLocation.Header
}; cfg.AddSecurityRequirement(new OpenApiSecurityRequirement
var requirement = new OpenApiSecurityRequirement
{ {
{ scheme, new List<string>() } //{
}; // new OpenApiSecurityScheme
cfg.AddSecurityRequirement(requirement); // {
// Reference = new OpenApiReference
// {
// Type = ReferenceType.SecurityScheme,
// Id = "ApiKey"
// },
// In = ParameterLocation.Header
// },
// new List<string>()
//},
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header
},
new List<string>()
}
});
}); });
builder.Services.AddDbContext<DatabaseContext>();
var app = builder.Build(); var app = builder.Build();
@ -88,9 +167,10 @@ app.UseHttpsRedirection();
app.UseHangfireDashboard(); app.UseHangfireDashboard();
BackgroundJobs.SetupRecurringJobs(config); BackgroundJobs.SetupRecurringJobs(config);
app.UseAuthorization(); //app.UseAuthorization();
app.UseAuthentication();
app.UseMiddleware<ApiKeyAuthAuthentication>(); //app.UseMiddleware<ApiKeyAuthAuthentication>();
app.MapHealthChecks("/health", new HealthCheckOptions app.MapHealthChecks("/health", new HealthCheckOptions
{ {

View File

@ -0,0 +1,114 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;
using Newsbot.Collector.Api.Domain.Results;
using Newsbot.Collector.Domain.Models.Config;
namespace Newsbot.Collector.Api.Services;
public interface IIdentityService
{
AuthenticationResult Register(string email, string password);
AuthenticationResult Login(string email, string password);
}
public class IdentityService : IIdentityService
{
private readonly UserManager<IdentityUser> _userManager;
private readonly JwtSettings _jwtSettings;
public IdentityService(UserManager<IdentityUser> userManager, JwtSettings jwtSettings)
{
_userManager = userManager;
_jwtSettings = jwtSettings;
}
public AuthenticationResult Register(string email, string password)
{
var userExists = _userManager.FindByEmailAsync(email);
userExists.Wait();
if (userExists.Result != null)
{
return new AuthenticationResult
{
ErrorMessage = new[] { "A user with this email address already exists" }
};
}
var newUser = new IdentityUser
{
UserName = email,
Email = email
};
var createdUser = _userManager.CreateAsync(newUser, password);
createdUser.Wait();
if (!createdUser.Result.Succeeded)
{
return new AuthenticationResult
{
ErrorMessage = new[] { createdUser.Result.Errors.Select(x => x.Description).ToString() }
};
}
return GenerateJwtToken(newUser);
}
public AuthenticationResult Login(string email, string password)
{
var user =_userManager.FindByEmailAsync(email);
user.Wait();
if (user.Result == null)
{
return new AuthenticationResult
{
ErrorMessage = new[] { "User does not exist" }
};
}
var hasValidPassword = _userManager.CheckPasswordAsync(user.Result ?? new IdentityUser(), password);
hasValidPassword.Wait();
if (!hasValidPassword.Result)
{
return new AuthenticationResult()
{
ErrorMessage = new[] { "Password is invalid" }
};
}
return GenerateJwtToken(user.Result ?? new IdentityUser());
}
private AuthenticationResult GenerateJwtToken(IdentityUser user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtSettings.Secret ?? "");
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Email ?? ""),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Email, user.Email ?? ""),
new Claim("id", user.Id)
}),
Expires = DateTime.UtcNow.AddHours(3),
SigningCredentials =
new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return new AuthenticationResult
{
IsSuccessful = true,
Token = tokenHandler.WriteToken(token)
};
}
}

View File

@ -1,3 +1,5 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Newsbot.Collector.Domain.Consts; using Newsbot.Collector.Domain.Consts;
@ -5,46 +7,60 @@ using Newsbot.Collector.Domain.Entities;
namespace Newsbot.Collector.Database; namespace Newsbot.Collector.Database;
public class DatabaseContext : DbContext public class DatabaseContext : IdentityDbContext
{ {
public DbSet<ArticlesEntity> Articles { get; set; } = null!; public DbSet<ArticlesEntity> Articles { get; set; } = null!;
public DbSet<DiscordNotificationEntity> DiscordNotification { get; set; } = null!;
public DbSet<DiscordQueueEntity> DiscordQueue { get; set; } = null!; public DbSet<DiscordQueueEntity> DiscordQueue { get; set; } = null!;
public DbSet<DiscordWebhookEntity> DiscordWebhooks { get; set; } = null!; public DbSet<DiscordWebhookEntity> DiscordWebhooks { get; set; } = null!;
public DbSet<IconEntity> Icons { get; set; } = null!; public DbSet<IconEntity> Icons { get; set; } = null!;
public DbSet<SourceEntity> Sources { get; set; } = null!; public DbSet<SourceEntity> Sources { get; set; } = null!;
public DbSet<SubscriptionEntity> Subscriptions { get; set; } = null!;
private string ConnectionString { get; set; }
public DatabaseContext(IConfiguration appsettings, string connectionString) public DbSet<UserSourceSubscriptionEntity> UserSourceSubscription { get; set; } = null!;
{
var connString = appsettings.GetConnectionString(ConfigConnectionStringConst.Database); private string ConnectionString { get; set; } = "";
ConnectionString = connString ?? "";
} //public DatabaseContext(IConfiguration appsettings, string connectionString)
//{
// var connString = appsettings.GetConnectionString(ConfigConnectionStringConst.Database);
// ConnectionString = connString ?? "";
//}
public DatabaseContext(string connectionString) public DatabaseContext(string connectionString)
{ {
ConnectionString = connectionString; ConnectionString = connectionString;
} }
public DatabaseContext(DbContextOptions<DatabaseContext> connectionString)
{
ConnectionString = "";
}
public DatabaseContext()
{
ConnectionString = "";
}
protected override void OnConfiguring(DbContextOptionsBuilder options) protected override void OnConfiguring(DbContextOptionsBuilder options)
{ {
options.UseNpgsql(ConnectionString); if (ConnectionString != "")
{
options.UseNpgsql(ConnectionString);
}
}
//public DatabaseContext(DbContextOptions<DatabaseContext> connectionString)
//{
// ConnectionString = "";
//}
//public DatabaseContext()
//{
// ConnectionString = "";
//}
public DatabaseContext(DbContextOptions<DatabaseContext> options)
: base(options)
{
//ConnectionString = "";
} }
public DatabaseContext(DbContextOptions<DatabaseContext> options, string connectionString) public DatabaseContext(DbContextOptions<DatabaseContext> options, string connectionString)
: base(options) : base(options)
{ {
ConnectionString = connectionString; //ConnectionString = connectionString;
} }
} }

View File

@ -0,0 +1,470 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Newsbot.Collector.Database;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Newsbot.Collector.Database.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20230629222603_identity")]
partial class identity
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.ArticlesEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AuthorImage")
.HasColumnType("text");
b.Property<string>("AuthorName")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("CodeIsCommit")
.HasColumnType("boolean");
b.Property<bool>("CodeIsRelease")
.HasColumnType("boolean");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("PubDate")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.Property<string>("Tags")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Thumbnail")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.HasColumnType("text");
b.Property<string>("Video")
.IsRequired()
.HasColumnType("text");
b.Property<int>("VideoHeight")
.HasColumnType("integer");
b.Property<int>("VideoWidth")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("Articles");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordQueueEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("ArticleId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("DiscordQueue");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordWebhookEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Channel")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Server")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("DiscordWebhooks");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.IconEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("FileName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Site")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("Icons");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.SourceEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Deleted")
.HasColumnType("boolean");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Site")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Source")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Tags")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("text");
b.Property<string>("YoutubeId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Sources");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.SubscriptionEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("CodeAllowCommits")
.HasColumnType("boolean");
b.Property<bool>("CodeAllowReleases")
.HasColumnType("boolean");
b.Property<Guid>("DiscordWebHookId")
.HasColumnType("uuid");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("Subscriptions");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,223 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Newsbot.Collector.Database.Migrations
{
/// <inheritdoc />
public partial class identity : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PasswordHash = table.Column<string>(type: "text", nullable: true),
SecurityStamp = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
PhoneNumber = table.Column<string>(type: "text", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RoleId = table.Column<string>(type: "text", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(type: "text", nullable: false),
RoleId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(type: "text", nullable: false),
LoginProvider = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}

View File

@ -0,0 +1,501 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Newsbot.Collector.Database;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Newsbot.Collector.Database.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20230710050618_SourcesRenamed")]
partial class SourcesRenamed
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.ArticlesEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AuthorImage")
.HasColumnType("text");
b.Property<string>("AuthorName")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("CodeIsCommit")
.HasColumnType("boolean");
b.Property<bool>("CodeIsRelease")
.HasColumnType("boolean");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("PubDate")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.Property<string>("Tags")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Thumbnail")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.HasColumnType("text");
b.Property<string>("Video")
.IsRequired()
.HasColumnType("text");
b.Property<int>("VideoHeight")
.HasColumnType("integer");
b.Property<int>("VideoWidth")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("Articles");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordNotificationEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("CodeAllowCommits")
.HasColumnType("boolean");
b.Property<bool>("CodeAllowReleases")
.HasColumnType("boolean");
b.Property<Guid>("DiscordWebHookId")
.HasColumnType("uuid");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("DiscordNotification");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordQueueEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("ArticleId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("DiscordQueue");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordWebhookEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Channel")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Server")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("DiscordWebhooks");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.IconEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("FileName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Site")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("Icons");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.SourceEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Deleted")
.HasColumnType("boolean");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Site")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Source")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Tags")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("text");
b.Property<string>("YoutubeId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Sources");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.UserSourceSubscriptionEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTimeOffset>("DateAdded")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserSourceSubscription");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.UserSourceSubscriptionEntity", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User")
.WithMany()
.HasForeignKey("UserId");
b.Navigation("User");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,82 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Newsbot.Collector.Database.Migrations
{
/// <inheritdoc />
public partial class SourcesRenamed : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Subscriptions");
migrationBuilder.CreateTable(
name: "DiscordNotification",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CodeAllowReleases = table.Column<bool>(type: "boolean", nullable: false),
CodeAllowCommits = table.Column<bool>(type: "boolean", nullable: false),
SourceId = table.Column<Guid>(type: "uuid", nullable: false),
DiscordWebHookId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_DiscordNotification", x => x.Id);
});
migrationBuilder.CreateTable(
name: "UserSourceSubscription",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
SourceId = table.Column<Guid>(type: "uuid", nullable: false),
DateAdded = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
UserId = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserSourceSubscription", x => x.Id);
table.ForeignKey(
name: "FK_UserSourceSubscription_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_UserSourceSubscription_UserId",
table: "UserSourceSubscription",
column: "UserId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "DiscordNotification");
migrationBuilder.DropTable(
name: "UserSourceSubscription");
migrationBuilder.CreateTable(
name: "Subscriptions",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CodeAllowCommits = table.Column<bool>(type: "boolean", nullable: false),
CodeAllowReleases = table.Column<bool>(type: "boolean", nullable: false),
DiscordWebHookId = table.Column<Guid>(type: "uuid", nullable: false),
SourceId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Subscriptions", x => x.Id);
});
}
}
}

View File

@ -0,0 +1,504 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Newsbot.Collector.Database;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Newsbot.Collector.Database.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20230710050913_DiscordNotificationOwnerAdded")]
partial class DiscordNotificationOwnerAdded
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.ArticlesEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AuthorImage")
.HasColumnType("text");
b.Property<string>("AuthorName")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("CodeIsCommit")
.HasColumnType("boolean");
b.Property<bool>("CodeIsRelease")
.HasColumnType("boolean");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("PubDate")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.Property<string>("Tags")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Thumbnail")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.HasColumnType("text");
b.Property<string>("Video")
.IsRequired()
.HasColumnType("text");
b.Property<int>("VideoHeight")
.HasColumnType("integer");
b.Property<int>("VideoWidth")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("Articles");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordNotificationEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("CodeAllowCommits")
.HasColumnType("boolean");
b.Property<bool>("CodeAllowReleases")
.HasColumnType("boolean");
b.Property<Guid>("DiscordWebHookId")
.HasColumnType("uuid");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("DiscordNotification");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordQueueEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("ArticleId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("DiscordQueue");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordWebhookEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Channel")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Server")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("DiscordWebhooks");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.IconEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("FileName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Site")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("Icons");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.SourceEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Deleted")
.HasColumnType("boolean");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Site")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Source")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Tags")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("text");
b.Property<string>("YoutubeId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Sources");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.UserSourceSubscriptionEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTimeOffset>("DateAdded")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserSourceSubscription");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.UserSourceSubscriptionEntity", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User")
.WithMany()
.HasForeignKey("UserId");
b.Navigation("User");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Newsbot.Collector.Database.Migrations
{
/// <inheritdoc />
public partial class DiscordNotificationOwnerAdded : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "UserId",
table: "DiscordNotification",
type: "text",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UserId",
table: "DiscordNotification");
}
}
}

View File

@ -17,11 +17,207 @@ namespace Newsbot.Collector.Database.Migrations
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "7.0.7") .HasAnnotation("ProductVersion", "7.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 63); .HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.ArticlesEntity", b => modelBuilder.Entity("Newsbot.Collector.Domain.Entities.ArticlesEntity", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -81,6 +277,32 @@ namespace Newsbot.Collector.Database.Migrations
b.ToTable("Articles"); b.ToTable("Articles");
}); });
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordNotificationEntity", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("CodeAllowCommits")
.HasColumnType("boolean");
b.Property<bool>("CodeAllowReleases")
.HasColumnType("boolean");
b.Property<Guid>("DiscordWebHookId")
.HasColumnType("uuid");
b.Property<Guid>("SourceId")
.HasColumnType("uuid");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("DiscordNotification");
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordQueueEntity", b => modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordQueueEntity", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -192,27 +414,86 @@ namespace Newsbot.Collector.Database.Migrations
b.ToTable("Sources"); b.ToTable("Sources");
}); });
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.SubscriptionEntity", b => modelBuilder.Entity("Newsbot.Collector.Domain.Entities.UserSourceSubscriptionEntity", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid"); .HasColumnType("uuid");
b.Property<bool>("CodeAllowCommits") b.Property<DateTimeOffset>("DateAdded")
.HasColumnType("boolean"); .HasColumnType("timestamp with time zone");
b.Property<bool>("CodeAllowReleases")
.HasColumnType("boolean");
b.Property<Guid>("DiscordWebHookId")
.HasColumnType("uuid");
b.Property<Guid>("SourceId") b.Property<Guid>("SourceId")
.HasColumnType("uuid"); .HasColumnType("uuid");
b.Property<string>("UserId")
.HasColumnType("text");
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("Subscriptions"); b.HasIndex("UserId");
b.ToTable("UserSourceSubscription");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Newsbot.Collector.Domain.Entities.UserSourceSubscriptionEntity", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User")
.WithMany()
.HasForeignKey("UserId");
b.Navigation("User");
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }

View File

@ -6,6 +6,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="dapper" Version="2.0.123" /> <PackageReference Include="dapper" Version="2.0.123" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.8"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@ -11,29 +11,34 @@ namespace Newsbot.Collector.Database.Repositories;
public class ArticlesTable : IArticlesRepository public class ArticlesTable : IArticlesRepository
{ {
private readonly string _connectionString; //private readonly string _connectionString;
private DatabaseContext _context; private DatabaseContext _context;
public ArticlesTable(string connectionString) public ArticlesTable(string connectionString)
{ {
_connectionString = connectionString; //_connectionString = connectionString;
_context = new DatabaseContext(connectionString); _context = new DatabaseContext(connectionString);
} }
public ArticlesTable(IConfiguration configuration) public ArticlesTable(DatabaseContext context)
{ {
var conn = configuration.GetConnectionString("database"); _context = context;
if (conn is null) conn = "";
_connectionString = conn;
_context = new DatabaseContext(conn);
} }
//public ArticlesTable(IConfiguration configuration)
//{
// var conn = configuration.GetConnectionString("database");
// if (conn is null) conn = "";
//
// _context = new DatabaseContext(conn);
//}
public List<ArticlesEntity> List(int page = 0, int count = 25) public List<ArticlesEntity> List(int page = 0, int count = 25)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var query = context.Articles
var query = _context.Articles
.Skip(page * count) .Skip(page * count)
.OrderBy(d => d.PubDate) .OrderBy(d => d.PubDate)
.Take(25); .Take(25);
@ -43,8 +48,8 @@ public class ArticlesTable : IArticlesRepository
public ArticlesEntity GetById(Guid id) public ArticlesEntity GetById(Guid id)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var query = context.Articles var query = _context.Articles
.FirstOrDefault(d => d.Id.Equals(id)); .FirstOrDefault(d => d.Id.Equals(id));
query ??= new ArticlesEntity(); query ??= new ArticlesEntity();
return query; return query;
@ -52,16 +57,16 @@ public class ArticlesTable : IArticlesRepository
public ArticlesEntity GetByUrl(string url) public ArticlesEntity GetByUrl(string url)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Articles.FirstOrDefault(d => d.Url!.Equals(url)); var res = _context.Articles.FirstOrDefault(d => d.Url!.Equals(url));
res ??= new ArticlesEntity(); res ??= new ArticlesEntity();
return res; return res;
} }
public List<ArticlesEntity> ListBySourceId(Guid id, int page, int count) public List<ArticlesEntity> ListBySourceId(Guid id, int page, int count)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Articles var res = _context.Articles
.Skip(page * count) .Skip(page * count)
.Where(d => d.SourceId.Equals(id)); .Where(d => d.SourceId.Equals(id));
return res.ToList(); return res.ToList();
@ -69,13 +74,14 @@ public class ArticlesTable : IArticlesRepository
public ArticlesEntity New(ArticlesEntity model) public ArticlesEntity New(ArticlesEntity model)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
model.Id = new Guid(); model.Id = new Guid();
var query = context.Articles.Add(model); var query = _context.Articles.Add(model);
context.SaveChanges(); _context.SaveChanges();
return model; return model;
} }
/*
public ArticlesModel NewDapper(ArticlesModel model) public ArticlesModel NewDapper(ArticlesModel model)
{ {
model.ID = Guid.NewGuid(); model.ID = Guid.NewGuid();
@ -103,26 +109,27 @@ public class ArticlesTable : IArticlesRepository
}); });
return model; return model;
} }
*/
public void DeleteAllBySourceId(Guid sourceId) public void DeleteAllBySourceId(Guid sourceId)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Articles var res = _context.Articles
.Where(d => d.SourceId.Equals(sourceId)) .Where(d => d.SourceId.Equals(sourceId))
.ToList(); .ToList();
foreach (var item in res) foreach (var item in res)
{ {
context.Articles.Remove(item); _context.Articles.Remove(item);
} }
context.SaveChanges(); _context.SaveChanges();
} }
private IDbConnection OpenConnection(string connectionString) //private IDbConnection OpenConnection(string connectionString)
{ //{
var conn = new NpgsqlConnection(_connectionString); // //var conn = new NpgsqlConnection(_connectionString);
conn.Open(); // //conn.Open();
return conn; // //return conn;
} //}
} }

View File

@ -0,0 +1,92 @@
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;
public class DiscordNotificationTable : IDiscordNotificationRepository
{
//private readonly string _connectionString;
private DatabaseContext _context;
public DiscordNotificationTable(string connectionString)
{
//_connectionString = connectionString;
_context = new DatabaseContext(connectionString);
}
public DiscordNotificationTable(DatabaseContext context)
{
_context = context;
}
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<DiscordNotificationEntity> List(int page = 0, int count = 25)
{
//using var context = new DatabaseContext(_connectionString);
return _context.DiscordNotification.Skip(page * count).Take(count).ToList();
}
public List<DiscordNotificationEntity> ListBySourceId(Guid id, int page = 0, int count = 25)
{
//using var context = new DatabaseContext(_connectionString);
return _context.DiscordNotification.Where(f => f.SourceId.Equals(id))
.Skip(page * count)
.ToList();
}
public List<DiscordNotificationEntity> ListByWebhook(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();
}
public DiscordNotificationEntity GetById(Guid id)
{
//using var context = new DatabaseContext(_connectionString);
var res = _context.DiscordNotification
.FirstOrDefault(f => f.Id.Equals(id));
return res ??= new DiscordNotificationEntity();
}
public DiscordNotificationEntity GetByWebhookAndSource(Guid webhookId, Guid sourceId)
{
//using var context = new DatabaseContext(_connectionString);
var res = _context.DiscordNotification
.Where(f => f.DiscordWebHookId.Equals(webhookId))
.FirstOrDefault(f => f.SourceId.Equals(sourceId));
return res ??= new DiscordNotificationEntity();
}
public void Delete(Guid id)
{
//using var context = new DatabaseContext(_connectionString);
var res = _context.DiscordNotification.FirstOrDefault(f => f.Id.Equals(id));
if (res is null)
{
return;
}
_context.DiscordNotification.Remove(res);
_context.SaveChanges();
}
//private IDbConnection OpenConnection(string connectionString)
//{
// var conn = new NpgsqlConnection(_connectionString);
// conn.Open();
// return conn;
//}
}

View File

@ -9,42 +9,49 @@ namespace Newsbot.Collector.Database.Repositories;
public class DiscordQueueTable : IDiscordQueueRepository public class DiscordQueueTable : IDiscordQueueRepository
{ {
private string _connectionString; //private string _connectionString;
private DatabaseContext _context;
public DiscordQueueTable(string connectionString) public DiscordQueueTable(string connectionString)
{ {
_connectionString = connectionString; //_connectionString = connectionString;
_context = new DatabaseContext(connectionString);
} }
private IDbConnection OpenConnection(string connectionString) public DiscordQueueTable(DatabaseContext context)
{ {
var conn = new NpgsqlConnection(_connectionString); _context = context;
conn.Open();
return conn;
} }
//private IDbConnection OpenConnection(string connectionString)
//{
// var conn = new NpgsqlConnection(_connectionString);
// conn.Open();
// return conn;
//}
public void New(DiscordQueueEntity model) public void New(DiscordQueueEntity model)
{ {
model.Id = new Guid(); model.Id = new Guid();
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.DiscordQueue.Add(model); var res = _context.DiscordQueue.Add(model);
context.SaveChanges(); _context.SaveChanges();
} }
public void Delete(Guid id) public void Delete(Guid id)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.DiscordQueue.FirstOrDefault(d => d.Id.Equals(id)); var res = _context.DiscordQueue.FirstOrDefault(d => d.Id.Equals(id));
res ??= new DiscordQueueEntity(); res ??= new DiscordQueueEntity();
context.DiscordQueue.Remove(res); _context.DiscordQueue.Remove(res);
context.SaveChanges(); _context.SaveChanges();
} }
public List<DiscordQueueEntity> List(int limit = 25) public List<DiscordQueueEntity> List(int limit = 25)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.DiscordQueue.Take(limit).ToList(); var res = _context.DiscordQueue.Take(limit).ToList();
return res; return res;
} }
} }

View File

@ -9,49 +9,50 @@ namespace Newsbot.Collector.Database.Repositories;
public class DiscordWebhooksTable : IDiscordWebHooksRepository public class DiscordWebhooksTable : IDiscordWebHooksRepository
{ {
private readonly string _connectionString; //private readonly string _connectionString;
private DatabaseContext _context;
public DiscordWebhooksTable(string connectionString) public DiscordWebhooksTable(string connectionString)
{ {
_connectionString = connectionString; //_connectionString = connectionString;
_context = new DatabaseContext(connectionString);
} }
public DiscordWebhooksTable(IConfiguration configuration) public DiscordWebhooksTable(DatabaseContext context)
{ {
var connstr = configuration.GetConnectionString("database") ?? ""; _context = context;
_connectionString = connstr;
} }
public DiscordWebhookEntity New(DiscordWebhookEntity model) public DiscordWebhookEntity New(DiscordWebhookEntity model)
{ {
model.Id = new Guid(); model.Id = new Guid();
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
context.DiscordWebhooks.Add(model); _context.DiscordWebhooks.Add(model);
context.SaveChanges(); _context.SaveChanges();
return model; return model;
} }
public DiscordWebhookEntity GetById(Guid id) public DiscordWebhookEntity GetById(Guid id)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.DiscordWebhooks.FirstOrDefault(d => d.Id.Equals(id)); var res = _context.DiscordWebhooks.FirstOrDefault(d => d.Id.Equals(id));
res ??= new DiscordWebhookEntity(); res ??= new DiscordWebhookEntity();
return res; return res;
} }
public DiscordWebhookEntity GetByUrl(string url) public DiscordWebhookEntity GetByUrl(string url)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.DiscordWebhooks.FirstOrDefault(d => d.Url.Equals(url)); var res = _context.DiscordWebhooks.FirstOrDefault(d => d.Url.Equals(url));
res ??= new DiscordWebhookEntity(); res ??= new DiscordWebhookEntity();
return res; return res;
} }
public List<DiscordWebhookEntity> List(int page, int count = 25) public List<DiscordWebhookEntity> List(int page, int count = 25)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.DiscordWebhooks var res = _context.DiscordWebhooks
.Skip(page * count) .Skip(page * count)
.Take(count) .Take(count)
.ToList(); .ToList();
@ -61,8 +62,8 @@ public class DiscordWebhooksTable : IDiscordWebHooksRepository
public List<DiscordWebhookEntity> ListByServer(string server, int limit = 25) public List<DiscordWebhookEntity> ListByServer(string server, int limit = 25)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.DiscordWebhooks var res = _context.DiscordWebhooks
.Where(d => d.Server.Equals(server)) .Where(d => d.Server.Equals(server))
.Take(limit) .Take(limit)
.ToList(); .ToList();
@ -72,8 +73,8 @@ public class DiscordWebhooksTable : IDiscordWebHooksRepository
public List<DiscordWebhookEntity> ListByServerAndChannel(string server, string channel, int limit = 25) public List<DiscordWebhookEntity> ListByServerAndChannel(string server, string channel, int limit = 25)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.DiscordWebhooks var res = _context.DiscordWebhooks
.Where(s => s.Server.Equals(server)) .Where(s => s.Server.Equals(server))
.Where(c => c.Channel.Equals(channel)) .Where(c => c.Channel.Equals(channel))
.Take(limit) .Take(limit)
@ -85,14 +86,14 @@ public class DiscordWebhooksTable : IDiscordWebHooksRepository
public int Disable(Guid id) public int Disable(Guid id)
{ {
var res = GetById(id); var res = GetById(id);
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
res.Enabled = true; res.Enabled = true;
context.DiscordWebhooks.Update(res); _context.DiscordWebhooks.Update(res);
try try
{ {
context.SaveChanges(); _context.SaveChanges();
return 1; return 1;
} }
catch(Exception ex) catch(Exception ex)
@ -105,14 +106,14 @@ public class DiscordWebhooksTable : IDiscordWebHooksRepository
public int Enable(Guid id) public int Enable(Guid id)
{ {
var res = GetById(id); var res = GetById(id);
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
res.Enabled = false; res.Enabled = false;
context.DiscordWebhooks.Update(res); _context.DiscordWebhooks.Update(res);
try try
{ {
context.SaveChanges(); _context.SaveChanges();
return 1; return 1;
} }
catch(Exception ex) catch(Exception ex)
@ -122,10 +123,10 @@ public class DiscordWebhooksTable : IDiscordWebHooksRepository
} }
} }
private IDbConnection OpenConnection(string connectionString) //private IDbConnection OpenConnection(string connectionString)
{ //{
var conn = new NpgsqlConnection(_connectionString); // var conn = new NpgsqlConnection(_connectionString);
conn.Open(); // conn.Open();
return conn; // return conn;
} //}
} }

View File

@ -10,49 +10,49 @@ namespace Newsbot.Collector.Database.Repositories;
public class IconsTable : IIconsRepository public class IconsTable : IIconsRepository
{ {
private readonly string _connectionString; //private readonly string _connectionString;
private DatabaseContext _context;
public IconsTable(string connectionString) public IconsTable(string connectionString)
{ {
_connectionString = connectionString; //_connectionString = connectionString;
_context = new DatabaseContext(connectionString);
} }
public IconsTable(IConfiguration configuration) public IconsTable(DatabaseContext context)
{ {
var connstr = configuration.GetConnectionString("database"); _context = context;
if (connstr is null) connstr = "";
_connectionString = connstr;
} }
public void New(IconEntity model) public void New(IconEntity model)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
model.Id = Guid.NewGuid(); model.Id = Guid.NewGuid();
context.Icons.Add(model); _context.Icons.Add(model);
context.SaveChanges(); _context.SaveChanges();
} }
public IconEntity GetById(Guid id) public IconEntity GetById(Guid id)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Icons.FirstOrDefault(f => f.Id.Equals(id)); var res = _context.Icons.FirstOrDefault(f => f.Id.Equals(id));
res ??= new IconEntity(); res ??= new IconEntity();
return res; return res;
} }
public IconEntity GetBySourceId(Guid id) public IconEntity GetBySourceId(Guid id)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Icons.FirstOrDefault(f => f.SourceId.Equals(id)); var res = _context.Icons.FirstOrDefault(f => f.SourceId.Equals(id));
res ??= new IconEntity(); res ??= new IconEntity();
return res; return res;
} }
private IDbConnection OpenConnection(string connectionString) //private IDbConnection OpenConnection(string connectionString)
{ //{
var conn = new NpgsqlConnection(_connectionString); // var conn = new NpgsqlConnection(_connectionString);
conn.Open(); // conn.Open();
return conn; // return conn;
} //}
} }

View File

@ -10,28 +10,28 @@ namespace Newsbot.Collector.Database.Repositories;
public class SourcesTable : ISourcesRepository public class SourcesTable : ISourcesRepository
{ {
private readonly string _connectionString; //private readonly string _connectionString;
private DatabaseContext _context;
public SourcesTable(string connectionString) public SourcesTable(string connectionString)
{ {
_connectionString = connectionString; //_connectionString = connectionString;
_context = new DatabaseContext(connectionString);
} }
public SourcesTable(IConfiguration configuration) public SourcesTable(DatabaseContext context)
{ {
var connstr = configuration.GetConnectionString("database"); _context = context;
if (connstr is null) connstr = "";
_connectionString = connstr;
} }
public SourceEntity New(SourceEntity model) public SourceEntity New(SourceEntity model)
{ {
model.Id = Guid.NewGuid(); model.Id = Guid.NewGuid();
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
context.Sources.Add(model); _context.Sources.Add(model);
try try
{ {
context.SaveChanges(); _context.SaveChanges();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -43,8 +43,8 @@ public class SourcesTable : ISourcesRepository
public SourceEntity GetById(Guid id) public SourceEntity GetById(Guid id)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Sources.FirstOrDefault(f => f.Id.Equals(id)); var res = _context.Sources.FirstOrDefault(f => f.Id.Equals(id));
res ??= new SourceEntity(); res ??= new SourceEntity();
return res; return res;
} }
@ -57,16 +57,16 @@ public class SourcesTable : ISourcesRepository
public SourceEntity GetByName(string name) public SourceEntity GetByName(string name)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Sources.FirstOrDefault(f => f.Name.Equals(name)); var res = _context.Sources.FirstOrDefault(f => f.Name.Equals(name));
res ??= new SourceEntity(); res ??= new SourceEntity();
return res; return res;
} }
public SourceEntity GetByNameAndType(string name, string type) public SourceEntity GetByNameAndType(string name, string type)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Sources var res = _context.Sources
.Where(f => f.Name.Equals(name)) .Where(f => f.Name.Equals(name))
.FirstOrDefault(f => f.Type.Equals(type)); .FirstOrDefault(f => f.Type.Equals(type));
res ??= new SourceEntity(); res ??= new SourceEntity();
@ -75,8 +75,8 @@ public class SourcesTable : ISourcesRepository
public SourceEntity GetByUrl(string url) public SourceEntity GetByUrl(string url)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Sources var res = _context.Sources
.FirstOrDefault(f => f.Url.Equals(url)); .FirstOrDefault(f => f.Url.Equals(url));
res ??= new SourceEntity(); res ??= new SourceEntity();
return res; return res;
@ -84,8 +84,8 @@ public class SourcesTable : ISourcesRepository
public List<SourceEntity> List(int page = 0, int count = 100) public List<SourceEntity> List(int page = 0, int count = 100)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Sources var res = _context.Sources
.Skip(page * count) .Skip(page * count)
.Take(count) .Take(count)
.ToList(); .ToList();
@ -94,8 +94,8 @@ public class SourcesTable : ISourcesRepository
public List<SourceEntity> ListBySource(string source, int page = 0, int limit = 25) public List<SourceEntity> ListBySource(string source, int page = 0, int limit = 25)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Sources var res = _context.Sources
.Where(f => f.Source.Equals(source)) .Where(f => f.Source.Equals(source))
.Skip(page * limit) .Skip(page * limit)
.Take(limit) .Take(limit)
@ -105,8 +105,8 @@ public class SourcesTable : ISourcesRepository
public List<SourceEntity> ListByType(string type,int page = 0, int limit = 25) public List<SourceEntity> ListByType(string type,int page = 0, int limit = 25)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = context.Sources var res = _context.Sources
.Where(f => f.Type.Equals(type)) .Where(f => f.Type.Equals(type))
.Skip(page * limit) .Skip(page * limit)
.Take(limit) .Take(limit)
@ -116,13 +116,13 @@ public class SourcesTable : ISourcesRepository
public int Disable(Guid id) public int Disable(Guid id)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = GetById(id); var res = GetById(id);
res.Enabled = false; res.Enabled = false;
context.Sources.Update(res); _context.Sources.Update(res);
try try
{ {
context.SaveChanges(); _context.SaveChanges();
return 1; return 1;
} }
catch catch
@ -133,13 +133,13 @@ public class SourcesTable : ISourcesRepository
public int Enable(Guid id) public int Enable(Guid id)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = GetById(id); var res = GetById(id);
res.Enabled = true; res.Enabled = true;
context.Sources.Update(res); _context.Sources.Update(res);
try try
{ {
context.SaveChanges(); _context.SaveChanges();
return 1; return 1;
} }
catch catch
@ -150,21 +150,21 @@ public class SourcesTable : ISourcesRepository
public void Delete(Guid id) public void Delete(Guid id)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = GetById(id); var res = GetById(id);
context.Sources.Remove(res); _context.Sources.Remove(res);
context.SaveChanges(); _context.SaveChanges();
} }
public int UpdateYoutubeId(Guid id, string youtubeId) public int UpdateYoutubeId(Guid id, string youtubeId)
{ {
using var context = new DatabaseContext(_connectionString); //using var context = new DatabaseContext(_connectionString);
var res = GetById(id); var res = GetById(id);
res.YoutubeId = youtubeId; res.YoutubeId = youtubeId;
context.Sources.Update(res); _context.Sources.Update(res);
try try
{ {
context.SaveChanges(); _context.SaveChanges();
return 1; return 1;
} }
catch catch
@ -173,10 +173,10 @@ public class SourcesTable : ISourcesRepository
} }
} }
private IDbConnection OpenConnection(string connectionString) //private IDbConnection OpenConnection(string connectionString)
{ //{
var conn = new NpgsqlConnection(_connectionString); // var conn = new NpgsqlConnection(_connectionString);
conn.Open(); // conn.Open();
return conn; // return conn;
} //}
} }

View File

@ -1,93 +0,0 @@
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;
public class SubscriptionsTable : ISubscriptionRepository
{
private readonly string _connectionString;
public SubscriptionsTable(string connectionString)
{
_connectionString = connectionString;
}
public SubscriptionsTable(IConfiguration configuration)
{
var connstr = configuration.GetConnectionString("database");
if (connstr is null) connstr = "";
_connectionString = connstr;
}
public SubscriptionEntity New(SubscriptionEntity model)
{
model.Id = new Guid();
using var context = new DatabaseContext(_connectionString);
context.Subscriptions.Add(model);
context.SaveChanges();
return model;
}
public List<SubscriptionEntity> List(int page = 0, int count = 25)
{
using var context = new DatabaseContext(_connectionString);
return context.Subscriptions.Skip(page * count).Take(count).ToList();
}
public List<SubscriptionEntity> ListBySourceId(Guid id, int page = 0, int count = 25)
{
using var context = new DatabaseContext(_connectionString);
return context.Subscriptions.Where(f => f.SourceId.Equals(id))
.Skip(page * count)
.ToList();
}
public List<SubscriptionEntity> ListByWebhook(Guid id, int page = 0, int count = 25)
{
using var context = new DatabaseContext(_connectionString);
return context.Subscriptions.Where(f => f.DiscordWebHookId.Equals(id)).Skip(page * count).ToList();
}
public SubscriptionEntity GetById(Guid id)
{
using var context = new DatabaseContext(_connectionString);
var res = context.Subscriptions
.FirstOrDefault(f => f.Id.Equals(id));
return res ??= new SubscriptionEntity();
}
public SubscriptionEntity GetByWebhookAndSource(Guid webhookId, Guid sourceId)
{
using var context = new DatabaseContext(_connectionString);
var res = context.Subscriptions
.Where(f => f.DiscordWebHookId.Equals(webhookId))
.FirstOrDefault(f => f.SourceId.Equals(sourceId));
return res ??= new SubscriptionEntity();
}
public void Delete(Guid id)
{
using var context = new DatabaseContext(_connectionString);
var res = context.Subscriptions.FirstOrDefault(f => f.Id.Equals(id));
if (res is null)
{
return;
}
context.Subscriptions.Remove(res);
context.SaveChanges();
}
private IDbConnection OpenConnection(string connectionString)
{
var conn = new NpgsqlConnection(_connectionString);
conn.Open();
return conn;
}
}

View File

@ -0,0 +1,26 @@
using Newsbot.Collector.Domain.Entities;
using Newsbot.Collector.Domain.Interfaces;
namespace Newsbot.Collector.Database.Repositories;
public class UserSourceSubscriptionTable : IUserSourceSubscription
{
private DatabaseContext _context;
public UserSourceSubscriptionTable(string connectionString)
{
_context = new DatabaseContext(connectionString);
}
public UserSourceSubscriptionTable(DatabaseContext context)
{
_context = context;
}
public List<UserSourceSubscriptionEntity> ListUserSubscriptions(Guid userId)
{
var results =_context.UserSourceSubscription.Where(i => i.UserId.Equals(userId)).ToList();
return results;
}
}

View File

@ -3,7 +3,7 @@ using Newsbot.Collector.Domain.Models;
namespace Newsbot.Collector.Domain.Dto; namespace Newsbot.Collector.Domain.Dto;
public class SubscriptionDetailsDto public class DiscordNotificationDetailsDto
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public bool CodeAllowReleases { get; set; } public bool CodeAllowReleases { get; set; }
@ -11,14 +11,14 @@ public class SubscriptionDetailsDto
public SourceDto? Source { get; set; } public SourceDto? Source { get; set; }
public DiscordWebHookDto? DiscordWebHook { get; set; } public DiscordWebHookDto? DiscordWebHook { get; set; }
public static SubscriptionDetailsDto Convert(SubscriptionEntity subscription, SourceEntity source, public static DiscordNotificationDetailsDto Convert(DiscordNotificationEntity discordNotification, SourceEntity source,
DiscordWebhookEntity discord) DiscordWebhookEntity discord)
{ {
return new SubscriptionDetailsDto return new DiscordNotificationDetailsDto
{ {
Id = subscription.Id, Id = discordNotification.Id,
CodeAllowCommits = subscription.CodeAllowCommits, CodeAllowCommits = discordNotification.CodeAllowCommits,
CodeAllowReleases = subscription.CodeAllowReleases, CodeAllowReleases = discordNotification.CodeAllowReleases,
Source = SourceDto.Convert(source), Source = SourceDto.Convert(source),
DiscordWebHook = DiscordWebHookDto.Convert(discord) DiscordWebHook = DiscordWebHookDto.Convert(discord)
}; };

View File

@ -3,7 +3,7 @@ using Newsbot.Collector.Domain.Models;
namespace Newsbot.Collector.Domain.Dto; namespace Newsbot.Collector.Domain.Dto;
public class SubscriptionDto public class DiscordNotificationDto
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public Guid SourceId { get; set; } public Guid SourceId { get; set; }
@ -11,9 +11,9 @@ public class SubscriptionDto
public bool CodeAllowReleases { get; set; } public bool CodeAllowReleases { get; set; }
public bool CodeAllowCommits { get; set; } public bool CodeAllowCommits { get; set; }
public static SubscriptionDto Convert(SubscriptionEntity model) public static DiscordNotificationDto Convert(DiscordNotificationEntity model)
{ {
return new SubscriptionDto return new DiscordNotificationDto
{ {
Id = model.Id, Id = model.Id,
SourceId = model.SourceId, SourceId = model.SourceId,

View File

@ -0,0 +1,7 @@
namespace Newsbot.Collector.Domain.Dto;
public class UserNewDto
{
public string? Username { get; set; }
public string? Password { get; set; }
}

View File

@ -1,6 +1,9 @@
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Identity;
namespace Newsbot.Collector.Domain.Entities; namespace Newsbot.Collector.Domain.Entities;
public class SubscriptionEntity public class DiscordNotificationEntity
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public bool CodeAllowReleases { get; set; } public bool CodeAllowReleases { get; set; }
@ -8,4 +11,8 @@ public class SubscriptionEntity
public Guid SourceId { get; set; } public Guid SourceId { get; set; }
public Guid DiscordWebHookId { get; set; } public Guid DiscordWebHookId { get; set; }
public string? UserId { get; set; }
//[ForeignKey(nameof(UserId))]
//public IdentityUser User { get; set; }
} }

View File

@ -0,0 +1,20 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Identity;
namespace Newsbot.Collector.Domain.Entities;
/// <summary>
/// This defines the sources a user will want to see as a feed.
/// </summary>
public class UserSourceSubscriptionEntity
{
[Key]
public Guid Id { get; set; }
public Guid SourceId { get; set; }
public DateTimeOffset DateAdded { get; set; }
public string? UserId { get; set; }
[ForeignKey(nameof(UserId))]
public IdentityUser? User { get; set; }
}

View File

@ -2,7 +2,7 @@ using Newsbot.Collector.Domain.Models;
namespace Newsbot.Collector.Domain.Interfaces; namespace Newsbot.Collector.Domain.Interfaces;
public interface IDiscordNotificatioClient public interface IDiscordClient
{ {
void SendMessage(DiscordMessage payload); void SendMessage(DiscordMessage payload);
} }

View File

@ -0,0 +1,18 @@
using Newsbot.Collector.Domain.Entities;
using Newsbot.Collector.Domain.Models;
namespace Newsbot.Collector.Domain.Interfaces;
public interface IDiscordNotificationRepository
{
DiscordNotificationEntity New(DiscordNotificationEntity model);
List<DiscordNotificationEntity> List(int page = 0, int count = 25);
List<DiscordNotificationEntity> ListBySourceId(Guid id, int page = 0, int count = 25);
List<DiscordNotificationEntity> ListByWebhook(Guid id, int page = 0, int count = 25);
DiscordNotificationEntity GetById(Guid id);
DiscordNotificationEntity GetByWebhookAndSource(Guid webhookId, Guid sourceId);
void Delete(Guid id);
}

View File

@ -1,18 +0,0 @@
using Newsbot.Collector.Domain.Entities;
using Newsbot.Collector.Domain.Models;
namespace Newsbot.Collector.Domain.Interfaces;
public interface ISubscriptionRepository
{
SubscriptionEntity New(SubscriptionEntity model);
List<SubscriptionEntity> List(int page = 0, int count = 25);
List<SubscriptionEntity> ListBySourceId(Guid id, int page = 0, int count = 25);
List<SubscriptionEntity> ListByWebhook(Guid id, int page = 0, int count = 25);
SubscriptionEntity GetById(Guid id);
SubscriptionEntity GetByWebhookAndSource(Guid webhookId, Guid sourceId);
void Delete(Guid id);
}

View File

@ -0,0 +1,8 @@
using Newsbot.Collector.Domain.Entities;
namespace Newsbot.Collector.Domain.Interfaces;
public interface IUserSourceSubscription
{
List<UserSourceSubscriptionEntity> ListUserSubscriptions(Guid userId);
}

View File

@ -0,0 +1,6 @@
namespace Newsbot.Collector.Domain.Models.Config;
public class JwtSettings
{
public string? Secret { get; set; }
}

View File

@ -1,4 +1,4 @@
namespace Newsbot.Collector.Domain.Models.Config; namespace Newsbot.Collector.Domain.Models.Config.Sources;
public class ConfigSectionRedditModel public class ConfigSectionRedditModel
{ {

View File

@ -1,4 +1,4 @@
namespace Newsbot.Collector.Domain.Models.Config; namespace Newsbot.Collector.Domain.Models.Config.Sources;
public class ConfigSectionRssModel public class ConfigSectionRssModel
{ {

View File

@ -1,4 +1,4 @@
namespace Newsbot.Collector.Domain.Models.Config; namespace Newsbot.Collector.Domain.Models.Config.Sources;
public class ConfigSectionYoutubeModel public class ConfigSectionYoutubeModel
{ {

View File

@ -7,7 +7,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="7.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="7.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup> </ItemGroup>

View File

@ -36,11 +36,19 @@ public class HtmlPageReader
private string ReadSiteContent(string url) private string ReadSiteContent(string url)
{ {
using var client = new HttpClient(); using var client = new HttpClient();
var html = client.GetStringAsync(url); try
html.Wait(); {
var html = client.GetStringAsync(url);
html.Wait();
var content = html.Result; var content = html.Result;
return content; return content;
}
catch (Exception ex)
{
Console.WriteLine($"Failed to connect to '{url}'. {ex.Message}");
return "";
}
} }
public string GetSiteContent() public string GetSiteContent()

View File

@ -1,3 +1,4 @@
using Newsbot.Collector.Database;
using Newsbot.Collector.Database.Repositories; using Newsbot.Collector.Database.Repositories;
using Newsbot.Collector.Domain.Entities; using Newsbot.Collector.Domain.Entities;
using Newsbot.Collector.Domain.Interfaces; using Newsbot.Collector.Domain.Interfaces;
@ -32,13 +33,13 @@ public class DiscordNotificationJobOptions
public class DiscordNotificationJob public class DiscordNotificationJob
{ {
private const string JobName = "DiscordNotifications"; private const string JobName = "DiscordNotifications";
private ILogger _logger;
//private DatabaseContext _databaseContext;
private IArticlesRepository _article; private IArticlesRepository _article;
private IIconsRepository _icons; private IIconsRepository _icons;
private ILogger _logger;
private IDiscordQueueRepository _queue; private IDiscordQueueRepository _queue;
private ISourcesRepository _sources; private ISourcesRepository _sources;
private ISubscriptionRepository _subs; private IDiscordNotificationRepository _subs;
private IDiscordWebHooksRepository _webhook; private IDiscordWebHooksRepository _webhook;
public DiscordNotificationJob() public DiscordNotificationJob()
@ -47,18 +48,19 @@ public class DiscordNotificationJob
_article = new ArticlesTable(""); _article = new ArticlesTable("");
_webhook = new DiscordWebhooksTable(""); _webhook = new DiscordWebhooksTable("");
_sources = new SourcesTable(""); _sources = new SourcesTable("");
_subs = new SubscriptionsTable(""); _subs = new DiscordNotificationTable("");
_icons = new IconsTable(""); _icons = new IconsTable("");
_logger = JobLogger.GetLogger("", JobName); _logger = JobLogger.GetLogger("", JobName);
} }
public void InitAndExecute(DiscordNotificationJobOptions options) public void InitAndExecute(DiscordNotificationJobOptions options)
{ {
//_databaseContext = new DatabaseContext(options.ConnectionString ?? "");
_queue = new DiscordQueueTable(options.ConnectionString ?? ""); _queue = new DiscordQueueTable(options.ConnectionString ?? "");
_article = new ArticlesTable(options.ConnectionString ?? ""); _article = new ArticlesTable(options.ConnectionString ?? "");
_webhook = new DiscordWebhooksTable(options.ConnectionString ?? ""); _webhook = new DiscordWebhooksTable(options.ConnectionString ?? "");
_sources = new SourcesTable(options.ConnectionString ?? ""); _sources = new SourcesTable(options.ConnectionString ?? "");
_subs = new SubscriptionsTable(options.ConnectionString ?? ""); _subs = new DiscordNotificationTable(options.ConnectionString ?? "");
_icons = new IconsTable(options.ConnectionString ?? ""); _icons = new IconsTable(options.ConnectionString ?? "");
_logger = JobLogger.GetLogger(options.OpenTelemetry ?? "", JobName); _logger = JobLogger.GetLogger(options.OpenTelemetry ?? "", JobName);
@ -76,6 +78,7 @@ public class DiscordNotificationJob
private void Execute() private void Execute()
{ {
//collect all the new requests //collect all the new requests
var requests = _queue.List(100); var requests = _queue.List(100);
_logger.Debug($"{JobName} - Collected {requests.Count} items to send"); _logger.Debug($"{JobName} - Collected {requests.Count} items to send");
@ -121,7 +124,7 @@ public class DiscordNotificationJob
_queue.Delete(request.Id); _queue.Delete(request.Id);
} }
public void SendSubscriptionNotification(Guid requestId, ArticlesEntity articleDetails, SourceEntity sourceDetails, IconEntity sourceIcon, SubscriptionEntity sub) public void SendSubscriptionNotification(Guid requestId, ArticlesEntity articleDetails, SourceEntity sourceDetails, IconEntity sourceIcon, DiscordNotificationEntity sub)
{ {
// Check if the subscription code flags // Check if the subscription code flags
// If the article is a code commit and the subscription does not want them, skip. // If the article is a code commit and the subscription does not want them, skip.
@ -134,7 +137,7 @@ public class DiscordNotificationJob
var discordDetails = _webhook.GetById(sub.DiscordWebHookId); var discordDetails = _webhook.GetById(sub.DiscordWebHookId);
if (discordDetails.Enabled == false) return; if (discordDetails.Enabled == false) return;
var client = new DiscordWebhookClient(discordDetails.Url); var client = new DiscordClient(discordDetails.Url);
try try
{ {
client.SendMessage(GenerateDiscordMessage(sourceDetails, articleDetails, sourceIcon)); client.SendMessage(GenerateDiscordMessage(sourceDetails, articleDetails, sourceIcon));

View File

@ -6,16 +6,16 @@ using Newtonsoft.Json;
namespace Newsbot.Collector.Services.Notifications.Discord; namespace Newsbot.Collector.Services.Notifications.Discord;
public class DiscordWebhookClient : IDiscordNotificatioClient public class DiscordClient : IDiscordClient
{ {
private readonly string[] _webhooks; private readonly string[] _webhooks;
public DiscordWebhookClient(string webhook) public DiscordClient(string webhook)
{ {
_webhooks = new[] { webhook }; _webhooks = new[] { webhook };
} }
public DiscordWebhookClient(string[] webhooks) public DiscordClient(string[] webhooks)
{ {
_webhooks = webhooks; _webhooks = webhooks;
} }

View File

@ -10,7 +10,7 @@ public class DiscordNotificationJobTest
public void PostTestMessage() public void PostTestMessage()
{ {
var uri = ""; var uri = "";
var webhookClient = new DiscordWebhookClient(uri); var webhookClient = new DiscordClient(uri);
var client = new DiscordNotificationJob(); var client = new DiscordNotificationJob();
var msg = client.GenerateDiscordMessage(new SourceEntity var msg = client.GenerateDiscordMessage(new SourceEntity
@ -78,7 +78,7 @@ public class DiscordNotificationJobTest
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
FileName = "https://www.redditstatic.com/desktop2x/img/favicon/android-icon-192x192.png" FileName = "https://www.redditstatic.com/desktop2x/img/favicon/android-icon-192x192.png"
}, },
new SubscriptionEntity new DiscordNotificationEntity
{ {
CodeAllowCommits = false, CodeAllowCommits = false,
CodeAllowReleases = true CodeAllowReleases = true

View File

@ -23,7 +23,8 @@ public class ArticlesTableTests
public void ArticlesListTest() public void ArticlesListTest()
{ {
var cfg = GetConfiguration(); var cfg = GetConfiguration();
var client = new ArticlesTable(cfg); var dbconn = cfg.GetConnectionString("Database");
var client = new ArticlesTable(dbconn ?? "");
client.List(0, 25); client.List(0, 25);
} }
@ -33,7 +34,8 @@ public class ArticlesTableTests
var uid = Guid.Parse("4ac46772-253c-4c3d-8a2c-29239abd2ad4"); var uid = Guid.Parse("4ac46772-253c-4c3d-8a2c-29239abd2ad4");
var cfg = GetConfiguration(); var cfg = GetConfiguration();
var client = new ArticlesTable(cfg); var dbconn = cfg.GetConnectionString("Database");
var client = new ArticlesTable(dbconn ?? "");
var res = client.GetById(uid); var res = client.GetById(uid);
if (!res.Id.Equals(uid)) if (!res.Id.Equals(uid))
{ {
@ -45,7 +47,8 @@ public class ArticlesTableTests
public void NewRecordTest() public void NewRecordTest()
{ {
var cfg = GetConfiguration(); var cfg = GetConfiguration();
var client = new ArticlesTable(cfg); var dbconn = cfg.GetConnectionString("Database");
var client = new ArticlesTable(dbconn ?? "");
var m = new ArticlesEntity var m = new ArticlesEntity
{ {
Id = Guid.NewGuid(), Id = Guid.NewGuid(),

View File

@ -0,0 +1,16 @@
using Microsoft.Extensions.Configuration;
using Newsbot.Collector.Database.Repositories;
using Newsbot.Collector.Domain.Consts;
namespace Newsbot.Collector.Tests.Tables;
public class DiscordQueueTableTests
{
[Fact]
public void TableListsData()
{
var str = TestHelper.LoadConfig().GetConnectionString("Database") ?? "";
var context = new DiscordQueueTable(str);
var results = context.List();
}
}