Fixed crash on initializing models, extended GetCategoriesAsync funtion

This commit is contained in:
Max 2023-06-10 19:06:30 +02:00
parent a17b2a7ebf
commit 4ff0f7c0c3
5 changed files with 99 additions and 102 deletions

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Data.Common; using System.Data.Common;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Security.Policy;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dapper; using Dapper;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
@ -14,17 +13,17 @@ namespace SharpRss
{ {
internal static class DbAccess internal static class DbAccess
{ {
static DbAccess()
{
Initialize();
}
private static readonly string ConnectionString = $"Data Source={Path.Combine(Environment.CurrentDirectory, "sharp_rss.sqlite")};"; private static readonly string ConnectionString = $"Data Source={Path.Combine(Environment.CurrentDirectory, "sharp_rss.sqlite")};";
private static bool _isInitialized; private static bool _isInitialized;
public static async Task SetSyndicationAsync(SyndicationContainer synContainer) public static async Task SetSyndicationAsync(SyndicationContainer synContainer)
{ {
if (synContainer.Category != null) if (synContainer.Category != null)
await SetCategoryAsync(synContainer.Category); {
CategoryModel? catModel = await SetCategoryAsync(synContainer.Category);
if (catModel != null)
synContainer.FeedModel.CategoryId = catModel.Id;
}
if (synContainer.FeedModel != null) if (synContainer.FeedModel != null)
await SetFeedAsync(synContainer.FeedModel); await SetFeedAsync(synContainer.FeedModel);
if (synContainer.FeedItems != null && synContainer.FeedItems.Any()) if (synContainer.FeedItems != null && synContainer.FeedItems.Any())
@ -51,14 +50,18 @@ namespace SharpRss
} }
return categories; return categories;
} }
public static async Task<bool> SetCategoryAsync(CategoryModel category) public static async Task<CategoryModel?> SetCategoryAsync(CategoryModel category)
{ {
if (category == null) return false; CategoryModel? modelReturn = null;
if (category == null) return modelReturn;
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
int affected = await dbc.ExecuteAsync("INSERT OR REPLACE INTO category (id, hex_color, icon, name) VALUES (IFNULL((SELECT id FROM category WHERE name=@Name), @Id), @HexColor, @Icon, @Name)", int affected = await dbc.ExecuteAsync("INSERT OR REPLACE INTO category (id, hex_color, icon, name) VALUES (IFNULL((SELECT id FROM category WHERE name=@Name), @Id), @HexColor, @Icon, @Name)",
new { category.Id, category.HexColor, category.Icon, category.Name }); new { category.Id, category.HexColor, category.Icon, category.Name });
return affected > 0; if (affected <= 0) return modelReturn;
var catModel = await GetCategoriesAsync();
modelReturn = catModel.Where(x => x.Name == category.Name).ToHashSet().FirstOrDefault() ?? null;
return modelReturn;
} }
public static async Task<bool> DeleteCategory(CategoryModel category) public static async Task<bool> DeleteCategory(CategoryModel category)
{ {
@ -73,7 +76,7 @@ namespace SharpRss
{ {
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
await using SqliteCommand cmd = new SqliteCommand(@"INSERT OR REPLACE INTO feed /*await using SqliteCommand cmd = new SqliteCommand(@"INSERT OR REPLACE INTO feed
(url, (url,
title, title,
category_id, category_id,
@ -116,8 +119,33 @@ namespace SharpRss
new SqliteParameter("ImageUrl", feed.ImageUrl ?? string.Empty) new SqliteParameter("ImageUrl", feed.ImageUrl ?? string.Empty)
} }
}; };
int exec = await cmd.ExecuteNonQueryAsync(); int exec = await cmd.ExecuteNonQueryAsync();*/
/*int affected = await dbc.ExecuteAsync("INSERT OR REPLACE INTO feed (url, title, category_id, feed_type, feed_version, description, language, copyright, publication_date, last_updated, categories, image_url) VALUES (@Url, @Title, @CategoryId, @FeedType, @FeedVersion, @Description, @language, @Copyright, @PublicationDate, @LastUpdated, @Categories, @ImageUrl)", int affected = await dbc.ExecuteAsync(@"INSERT OR REPLACE INTO feed
(url,
title,
category_id,
feed_type,
feed_version,
description,
language,
copyright,
publication_date,
last_updated,
categories,
image_url)
VALUES (
@Url,
@Title,
@CategoryId,
@FeedType,
@FeedVersion,
@Description,
@Language,
@Copyright,
@PublicationDate,
@LastUpdated,
@Categories,
@ImageUrl)",
new new
{ {
Url = feed.OriginalUrl ?? string.Empty, Url = feed.OriginalUrl ?? string.Empty,
@ -130,18 +158,18 @@ namespace SharpRss
Copyright = feed.Copyright ?? string.Empty, Copyright = feed.Copyright ?? string.Empty,
PublicationDate = feed.PublicationDate?.ToUnixTimeMilliseconds() ?? 0, PublicationDate = feed.PublicationDate?.ToUnixTimeMilliseconds() ?? 0,
LastUpdated = feed.LastUpdated?.ToUnixTimeMilliseconds() ?? 0, LastUpdated = feed.LastUpdated?.ToUnixTimeMilliseconds() ?? 0,
Categories = feed.Categories.Any() ? string.Join(',', feed.Categories) : string.Empty, Categories = feed.Categories != null && feed.Categories.Any() ? string.Join(',', feed.Categories) : string.Empty,
ImageUrl = feed.ImageUrl ?? string.Empty ImageUrl = feed.ImageUrl ?? string.Empty
}); });
if (affected == 0) if (affected == 0)
Log.Warning("Failed to add feed: {FeedUrl}", feed.OriginalUrl);*/ Log.Warning("Failed to add feed: {FeedUrl}", feed.OriginalUrl);
} }
public static async Task<HashSet<FeedModel>> GetFeedsAsync(string[]? categoryIds = null) public static async Task<HashSet<FeedModel>> GetFeedsAsync(string[]? categoryIds = null)
{ {
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
HashSet<FeedModel> feeds = new HashSet<FeedModel>(); HashSet<FeedModel> feeds = new HashSet<FeedModel>();
await using DbDataReader reader = await dbc.ExecuteReaderAsync(categoryIds == null ? "SELECT * FROM feed" : "SELECT * FROM feed WHERE category_id IN(@CatIds)", new { CatIds = categoryIds }); await using DbDataReader reader = await dbc.ExecuteReaderAsync(categoryIds == null ? "SELECT * FROM feed WHERE category_id == ''" : "SELECT * FROM feed WHERE category_id IN(@CatIds)", new { CatIds = categoryIds });
while (await reader.ReadAsync()) while (await reader.ReadAsync())
{ {
FeedModel feedModel = new FeedModel() FeedModel feedModel = new FeedModel()
@ -172,7 +200,7 @@ namespace SharpRss
await using SqliteTransaction dbTransaction = dbc.BeginTransaction(); await using SqliteTransaction dbTransaction = dbc.BeginTransaction();
foreach (FeedItemModel item in items) foreach (FeedItemModel item in items)
{ {
await using SqliteCommand cmd = new SqliteCommand(@"INSERT OR REPLACE INTO feed_item (id, feed_url, read, title, description, link, last_updated, publishing_date, authors, categories, content) /*await using SqliteCommand cmd = new SqliteCommand(@"INSERT OR REPLACE INTO feed_item (id, feed_url, read, title, description, link, last_updated, publishing_date, authors, categories, content)
VALUES (@Id, @FeedUrl, @Read, @Title, @Description, @Link, @LastUpdated, @PublishingDate, @Authors, @Categories, @Content)", dbc, dbTransaction) VALUES (@Id, @FeedUrl, @Read, @Title, @Description, @Link, @LastUpdated, @PublishingDate, @Authors, @Categories, @Content)", dbc, dbTransaction)
{ {
Parameters = Parameters =
@ -190,8 +218,8 @@ namespace SharpRss
new SqliteParameter("Content", item.Content ?? string.Empty) new SqliteParameter("Content", item.Content ?? string.Empty)
} }
}; };
int exec = await cmd.ExecuteNonQueryAsync(); int exec = await cmd.ExecuteNonQueryAsync();*/
/*int affected = await dbc.ExecuteAsync(@"INSERT OR REPLACE INTO feed_item (id, feed_url, read, title, description, link, last_updated, publishing_date, authors, categories, content) int affected = await dbc.ExecuteAsync(@"INSERT OR REPLACE INTO feed_item (id, feed_url, read, title, description, link, last_updated, publishing_date, authors, categories, content)
VALUES (@Id, @FeedUrl, @Read, @Title, @Description, @Link, @LastUpdated, @PublishingDate, @Authors, @Categories, @Content)", VALUES (@Id, @FeedUrl, @Read, @Title, @Description, @Link, @LastUpdated, @PublishingDate, @Authors, @Categories, @Content)",
transaction: dbTransaction, transaction: dbTransaction,
param: new param: new
@ -204,11 +232,11 @@ namespace SharpRss
Link = item.Link ?? string.Empty, Link = item.Link ?? string.Empty,
LastUpdated = item.LastUpdated?.ToUnixTimeMilliseconds() ?? 0, LastUpdated = item.LastUpdated?.ToUnixTimeMilliseconds() ?? 0,
PublishingDate = item.PublishingDate?.ToUnixTimeMilliseconds() ?? 0, PublishingDate = item.PublishingDate?.ToUnixTimeMilliseconds() ?? 0,
Authors = item.Authors.Any() ? string.Join(',', item.Authors) : string.Empty, Authors = item.Authors != null && item.Authors.Any() ? string.Join(',', item.Authors) : string.Empty,
Categories = item.Categories.Any() ? string.Join(',', item.Categories) : string.Empty, Categories = item.Categories != null && item.Categories.Any() ? string.Join(',', item.Categories) : string.Empty,
Content = item.Content ?? string.Empty Content = item.Content ?? string.Empty
}); });
totalAffected += affected;*/ totalAffected += affected;
} }
dbTransaction.Commit(); dbTransaction.Commit();
} }
@ -239,7 +267,7 @@ namespace SharpRss
return items; return items;
} }
private static async void Initialize() public static async void Initialize()
{ {
if (_isInitialized) return; if (_isInitialized) return;
Log.Verbose("Checking database..."); Log.Verbose("Checking database...");

View File

@ -79,42 +79,7 @@ namespace SharpRss.Services
var items = await DbAccess.GetFeedItemsAsync(feedIds); var items = await DbAccess.GetFeedItemsAsync(feedIds);
return items; return items;
} }
/*private async Task<int> AddFeedItems(IList<FeedItem> items, FeedModel feedModel)
{
int result = 0;
if (!items.Any())
return result;
HashSet<FeedItemModel> itemModels = new HashSet<FeedItemModel>();
// TODO: implement!!!
result = await DbAccess.SetFeedItemsAsync(itemModels);
return result;
}*/
/*private IList<FeedItemModel> ConstructFeedItems(IList<FeedItem> items, FeedModel feed)
{
IList<FeedItemModel> itemModels = new List<FeedItemModel>();
if (!items.Any())
return itemModels;
foreach (FeedItem item in items)
{
itemModels.Add(new FeedItemModel()
{
Id = item.Id,
FeedId = feed.Id,
Title = item.Title,
Description = item.Description,
Link = item.Link,
LastUpdated = DateTimeOffset.Now,
PublishingDate = item.PublishingDate != null ? new DateTimeOffset((DateTime)item.PublishingDate) : null,
Author = item.Author,
Categories = item.Categories.ToArray(),
Content = item.Content
});
}
return itemModels;
}*/
private GenericSyndicationFeed? CreateFeed(string url) private GenericSyndicationFeed? CreateFeed(string url)
{ {
Uri feedUri = new Uri(url); Uri feedUri = new Uri(url);
@ -129,9 +94,7 @@ namespace SharpRss.Services
} }
private async void SetupTestGroupsAndFeedsAsync() private async void SetupTestGroupsAndFeedsAsync()
{ {
/*CategoryModel newModel = new CategoryModel() { Name = "Test" }; /*await AddSubscriptionAsync("https://www.nu.nl/rss/Algemeen");*/
bool added = await DbAccess.SetCategoryAsync(newModel);*/
await AddSubscriptionAsync("https://en.wikipedia.org/w/api.php?hidebots=1&hidecategorization=1&hideWikibase=1&urlversion=1&days=7&limit=50&action=feedrecentchanges&feedformat=atom");
//TODO: Make multiple adding of feed to a transaction, now throws an exception. //TODO: Make multiple adding of feed to a transaction, now throws an exception.
/*var groupRes = await CreateGroupAsync(new GroupModel() { Name = "Test" }); /*var groupRes = await CreateGroupAsync(new GroupModel() { Name = "Test" });
groupRes = await CreateGroupAsync(new GroupModel() { Name = "News" }); groupRes = await CreateGroupAsync(new GroupModel() { Name = "News" });

View File

@ -61,62 +61,63 @@ namespace SharpRss
{ {
case SyndicationContentFormat.Rss: case SyndicationContentFormat.Rss:
RssFeed rssFeed = (RssFeed)container.SyndicationFeed.Resource; RssFeed rssFeed = (RssFeed)container.SyndicationFeed.Resource;
container.FeedModel.OriginalUrl = rssFeed.Channel.SelfLink.ToString(); if (rssFeed.Channel == null) break;
container.FeedModel.Title = rssFeed.Channel.Title; container.FeedModel.OriginalUrl = rssFeed.Channel.SelfLink?.ToString() ?? string.Empty;
container.FeedModel.FeedType = rssFeed.Format.ToString(); container.FeedModel.Title = rssFeed.Channel.Title ?? string.Empty;
container.FeedModel.FeedVersion = rssFeed.Version.ToString(); container.FeedModel.FeedType = rssFeed.Format.ToString() ?? string.Empty;
container.FeedModel.Description = rssFeed.Channel.Description; container.FeedModel.FeedVersion = rssFeed.Version?.ToString() ?? string.Empty;
container.FeedModel.Language = rssFeed.Channel.Language?.ToString(); container.FeedModel.Description = rssFeed.Channel.Description ?? string.Empty;
container.FeedModel.Copyright = rssFeed.Channel.Copyright; container.FeedModel.Language = rssFeed.Channel.Language?.ToString() ?? string.Empty;
container.FeedModel.PublicationDate = rssFeed.Channel.LastBuildDate.Ticks <= 0 ? DateTimeOffset.MinValue : new DateTimeOffset(rssFeed.Channel.LastBuildDate); container.FeedModel.Copyright = rssFeed.Channel.Copyright ?? string.Empty;
container.FeedModel.Categories = rssFeed.Channel.Categories.Select(x => x.Value).ToArray(); container.FeedModel.PublicationDate = rssFeed.Channel.LastBuildDate is not { Ticks: > 0 } ? DateTimeOffset.MinValue : new DateTimeOffset(rssFeed.Channel.LastBuildDate);
container.FeedModel.Categories = rssFeed.Channel.Categories?.Select(x => x.Value).ToArray() ?? Array.Empty<string>();
container.FeedModel.ImageUrl = rssFeed.Channel.Image?.Url.ToString() ?? string.Empty; container.FeedModel.ImageUrl = rssFeed.Channel.Image?.Url.ToString() ?? string.Empty;
foreach (var rssItem in rssFeed.Channel.Items) foreach (var rssItem in rssFeed.Channel.Items)
{ {
FeedItemModel itemModel = new FeedItemModel() FeedItemModel itemModel = new FeedItemModel()
{ {
Id = rssItem.Link.ToString(), Id = rssItem.Link?.ToString() ?? string.Empty,
FeedUrl = container.FeedModel.OriginalUrl, FeedUrl = container.FeedModel.OriginalUrl ?? string.Empty,
Type = container.FeedModel.FeedType, Type = container.FeedModel.FeedType ?? string.Empty,
Title = rssItem.Title, Title = rssItem.Title ?? string.Empty,
Description = rssItem.Description, Description = rssItem.Description ?? string.Empty,
Link = rssItem.Link.ToString(), Link = rssItem.Link?.ToString() ?? string.Empty,
PublishingDate = rssItem.PublicationDate.Ticks <= 0 ? DateTimeOffset.MinValue : new DateTimeOffset(rssItem.PublicationDate), PublishingDate = rssItem.PublicationDate is not { Ticks: <= 0 } ? DateTimeOffset.MinValue : new DateTimeOffset(rssItem.PublicationDate),
Authors = new []{ rssItem.Author }, Authors = rssItem.Author != null ? new []{ rssItem.Author } : Array.Empty<string>(),
Categories = rssItem.Categories.Select(x => x.Value).ToArray(), Categories = rssItem.Categories?.Select(x => x.Value).ToArray() ?? Array.Empty<string>(),
Content = rssItem.Extensions.Where(x => x is SiteSummaryContentSyndicationExtension).Select(x => (x as SiteSummaryContentSyndicationExtension)?.Context.Encoded).First(), Content = rssItem.Extensions?.Where(x => x is SiteSummaryContentSyndicationExtension).Select(x => (x as SiteSummaryContentSyndicationExtension)?.Context.Encoded).FirstOrDefault() ?? string.Empty,
CommentsUrl = rssItem.Extensions.Where(x => x is WellFormedWebCommentsSyndicationExtension).Select(x => (x as WellFormedWebCommentsSyndicationExtension)?.Context.CommentsFeed.ToString()).First() CommentsUrl = rssItem.Extensions?.Where(x => x is WellFormedWebCommentsSyndicationExtension).Select(x => (x as WellFormedWebCommentsSyndicationExtension)?.Context.CommentsFeed.ToString()).FirstOrDefault() ?? string.Empty
}; };
container.FeedItems.Add(itemModel); container.FeedItems.Add(itemModel);
} }
break; break;
case SyndicationContentFormat.Atom: case SyndicationContentFormat.Atom:
AtomFeed atomFeed = (AtomFeed)container.SyndicationFeed.Resource; AtomFeed atomFeed = (AtomFeed)container.SyndicationFeed.Resource;
container.FeedModel.OriginalUrl = atomFeed.Id.Uri.ToString(); container.FeedModel.OriginalUrl = atomFeed.Id?.Uri.ToString() ?? string.Empty;
container.FeedModel.Title = atomFeed.Title.Content; container.FeedModel.Title = atomFeed.Title?.Content ?? string.Empty;
container.FeedModel.FeedType = atomFeed.Format.ToString(); container.FeedModel.FeedType = atomFeed.Format.ToString() ?? string.Empty;
container.FeedModel.FeedVersion = atomFeed.Version?.ToString(); container.FeedModel.FeedVersion = atomFeed.Version?.ToString() ?? string.Empty;
container.FeedModel.Description = atomFeed.Subtitle?.Content; container.FeedModel.Description = atomFeed.Subtitle?.Content ?? string.Empty;
container.FeedModel.Language = atomFeed.Language?.ToString(); container.FeedModel.Language = atomFeed.Language?.ToString() ?? string.Empty;
container.FeedModel.Copyright = atomFeed.Rights?.Content; container.FeedModel.Copyright = atomFeed.Rights?.Content ?? string.Empty;
container.FeedModel.PublicationDate = new DateTimeOffset(atomFeed.UpdatedOn); container.FeedModel.PublicationDate = atomFeed.UpdatedOn != null ? new DateTimeOffset(atomFeed.UpdatedOn) : DateTimeOffset.MinValue;
container.FeedModel.Categories = atomFeed.Categories?.Select(x => x.Label).ToArray(); container.FeedModel.Categories = atomFeed.Categories?.Select(x => x.Label).ToArray() ?? Array.Empty<string>();
container.FeedModel.ImageUrl = atomFeed.Icon?.Uri.ToString() ?? string.Empty; container.FeedModel.ImageUrl = atomFeed.Icon?.Uri.ToString() ?? string.Empty;
foreach (var entry in atomFeed.Entries) foreach (var entry in atomFeed.Entries)
{ {
FeedItemModel itemModel = new FeedItemModel() FeedItemModel itemModel = new FeedItemModel()
{ {
Id = entry.Id.Uri.ToString(), Id = entry.Id?.Uri.ToString() ?? string.Empty,
FeedUrl = container.FeedModel.OriginalUrl, FeedUrl = container.FeedModel?.OriginalUrl ?? string.Empty,
Type = container.FeedModel.FeedType, Type = container.FeedModel?.FeedType ?? string.Empty,
Title = entry.Title.Content, Title = entry.Title?.Content ?? string.Empty,
Description = entry.Summary.Content, Description = entry.Summary?.Content ?? string.Empty,
Link = entry.Id.Uri.ToString(), Link = entry.Id?.Uri.ToString() ?? string.Empty,
LastUpdated = entry.UpdatedOn.Ticks <= 0 ? DateTimeOffset.MinValue : new DateTimeOffset(entry.UpdatedOn), LastUpdated = entry.UpdatedOn is not { Ticks: <= 0 } ? DateTimeOffset.MinValue : new DateTimeOffset(entry.UpdatedOn),
PublishingDate = entry.PublishedOn.Ticks <= 0 ? DateTimeOffset.MinValue : new DateTimeOffset(entry.PublishedOn), PublishingDate = entry.PublishedOn is not { Ticks: <= 0 } ? DateTimeOffset.MinValue : new DateTimeOffset(entry.PublishedOn),
Authors = entry.Authors.Select(auth => auth.Name).ToArray(), Authors = entry.Authors?.Select(auth => auth.Name).ToArray() ?? Array.Empty<string>(),
Categories = entry.Categories.Select(cat => cat.Label).ToArray(), Categories = entry.Categories?.Select(cat => cat.Label).ToArray() ?? Array.Empty<string>(),
Content = entry.Content?.Content Content = entry.Content?.Content ?? string.Empty
}; };
container.FeedItems.Add(itemModel); container.FeedItems.Add(itemModel);
} }
@ -128,5 +129,10 @@ namespace SharpRss
container.Fetched = true; container.Fetched = true;
return container; return container;
} }
public static void Init()
{
DbAccess.Initialize();
}
} }
} }

View File

@ -19,7 +19,7 @@ namespace WebSharpRSS
Caretaker.Settings.SetAppDefaultSettings(); Caretaker.Settings.SetAppDefaultSettings();
SetupLogging(); SetupLogging();
Log.Information("Starting SharpRSS..."); Log.Information("Starting SharpRSS...");
//DbAccess_Old.Initialize(); SyndicationManager.Init();
_bootstrapped = true; _bootstrapped = true;
} }

Binary file not shown.