Reworking db & Syndication implementation

This commit is contained in:
Max Holleman 2023-06-01 15:55:15 +02:00
parent 924e174240
commit 1f0e8840c1
9 changed files with 75 additions and 58 deletions

View File

@ -21,9 +21,8 @@ namespace SharpRss
private const string FeedItemTable = "feed_item_data"; private const string FeedItemTable = "feed_item_data";
// Groups // Groups
public static async Task<HashSet<GroupModel>> GetGroupsAsync(string? groupId = null) public static async Task<HashSet<CategoryModel>> GetGroupsAsync(string? groupId = null)
{ {
CheckInitialized();
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
await using SqliteCommand cmd = new SqliteCommand(groupId != null ? $"SELECT * FROM {GroupTable} WHERE id=@gId;" : $"SELECT * FROM {GroupTable}", dbc) await using SqliteCommand cmd = new SqliteCommand(groupId != null ? $"SELECT * FROM {GroupTable} WHERE id=@gId;" : $"SELECT * FROM {GroupTable}", dbc)
@ -34,7 +33,7 @@ namespace SharpRss
} }
}; };
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync(); await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
HashSet<GroupModel> groups = new HashSet<GroupModel>(); HashSet<CategoryModel> groups = new HashSet<CategoryModel>();
await using SqliteCommand cmdFeedCount = new SqliteCommand($"SELECT COUNT(*) FROM {FeedTable} WHERE group_id=@groupId", dbc); await using SqliteCommand cmdFeedCount = new SqliteCommand($"SELECT COUNT(*) FROM {FeedTable} WHERE group_id=@groupId", dbc);
while (reader.Read()) while (reader.Read())
{ {
@ -43,7 +42,7 @@ namespace SharpRss
using SqliteDataReader countReader = await cmdFeedCount.ExecuteReaderAsync(); using SqliteDataReader countReader = await cmdFeedCount.ExecuteReaderAsync();
int count = countReader.Read() ? countReader.GetInt32(0) : 0; int count = countReader.Read() ? countReader.GetInt32(0) : 0;
groups.Add(new GroupModel() groups.Add(new CategoryModel()
{ {
Name = reader["name"].ToString(), Name = reader["name"].ToString(),
FeedCount = count, FeedCount = count,
@ -54,7 +53,7 @@ namespace SharpRss
} }
return groups; return groups;
} }
public static async Task<bool> SetGroupAsync(GroupModel groupModel) public static async Task<bool> SetGroupAsync(CategoryModel groupModel)
{ {
bool result = false; bool result = false;
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
@ -74,7 +73,7 @@ namespace SharpRss
result = true; result = true;
return result; return result;
} }
public static async Task<bool> RemoveGroupAsync(GroupModel groupModel) public static async Task<bool> RemoveGroupAsync(CategoryModel groupModel)
{ {
bool result = false; bool result = false;
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
@ -93,6 +92,7 @@ namespace SharpRss
return result; return result;
} }
// Feeds // Feeds
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@ -115,14 +115,15 @@ namespace SharpRss
feeds.Add(await ReaderToFeedModel(reader)); feeds.Add(await ReaderToFeedModel(reader));
return feeds; return feeds;
} }
public static async Task<FeedModel?> GetFeedAsync(string feedId) public static async Task<FeedModel?> GetFeedAsync(string url)
{ {
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
FeedModel? feed = null; FeedModel? feed = null;
await using SqliteCommand cmd = new SqliteCommand($"SELECT * FROM {FeedTable} WHERE id=@id", dbc) //TODO: Use dapper to simplify this query.
await using SqliteCommand cmd = new SqliteCommand($"SELECT * FROM {FeedTable} WHERE url=@Url", dbc)
{ {
Parameters = { new SqliteParameter("id", feedId) } Parameters = { new SqliteParameter("Url", url) }
}; };
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync(); await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
if (reader.Read()) if (reader.Read())
@ -241,7 +242,7 @@ namespace SharpRss
}; };
if (feedItemModel is { FeedId: { } }) if (feedItemModel is { FeedId: { } })
{ {
FeedModel? feedModel = await GetFeedAsync(feedItemModel.FeedId); FeedModel? feedModel = await GetFeedAsync(feedItemModel.FeedUrl);
feedItemModel.Feed = feedModel; feedItemModel.Feed = feedModel;
} }
feedItems.Add(feedItemModel); feedItems.Add(feedItemModel);
@ -303,9 +304,9 @@ namespace SharpRss
result = true; result = true;
return result; return result;
} }
public static async Task<GroupModel?> GetGroupFromFeedItemAsync(FeedItemModel feedItem) public static async Task<CategoryModel?> GetGroupFromFeedItemAsync(FeedItemModel feedItem)
{ {
GroupModel? result = null; CategoryModel? result = null;
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
await using SqliteCommand cmd = new SqliteCommand($"SELECT * FROM {GroupTable} WHERE id=(SELECT group_id FROM {FeedTable} WHERE id=@fId)", dbc) await using SqliteCommand cmd = new SqliteCommand($"SELECT * FROM {GroupTable} WHERE id=(SELECT group_id FROM {FeedTable} WHERE id=@fId)", dbc)
@ -316,7 +317,7 @@ namespace SharpRss
} }
}; };
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync(); await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
HashSet<GroupModel>? groups = null; HashSet<CategoryModel>? groups = null;
if (reader.Read()) if (reader.Read())
groups = await GetGroupsAsync(reader["group_id"].ToString()); groups = await GetGroupsAsync(reader["group_id"].ToString());
if (groups != null && groups.Any()) if (groups != null && groups.Any())
@ -348,10 +349,6 @@ namespace SharpRss
} }
//=== //===
private static void CheckInitialized()
{
if (!_isInitialized) throw new TypeInitializationException(nameof(DbAccess), null);
}
public static async void Initialize() public static async void Initialize()
{ {
if (_isInitialized) return; if (_isInitialized) return;
@ -359,17 +356,17 @@ namespace SharpRss
HashSet<string> failed = new HashSet<string>(); HashSet<string> failed = new HashSet<string>();
await using SqliteConnection dbc = new SqliteConnection(ConnectionString); await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open(); dbc.Open();
Log.Verbose("Checking table: {Table}", GroupTable); Log.Verbose("Checking table: {Table}", "category");
var queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS {GroupTable} (name STRING NOT NULL, hex_color STRING NOT NULL, icon STRING, id STRING PRIMARY KEY)"); var queryResponse = await dbc.QueryAsync("CREATE TABLE IF NOT EXISTS category (name STRING NOT NULL, hex_color STRING NOT NULL, icon STRING, id STRING PRIMARY KEY)");
if (queryResponse.Any()) failed.Add("category_data"); if (queryResponse.Any()) failed.Add("category");
Log.Verbose("Checking table: {Table}", FeedTable); Log.Verbose("Checking table: {Table}", "feed");
queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS {FeedTable} (id STRING PRIMARY KEY, url STRING NOT NULL, title STRING, group_id STRING, feed_type STRING, description STRING, language STRING, copyright STRING, date_added INT, last_updated INT, image_url STRING, original_document STRING)"); queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed (url STRING PRIMARY KEY, title STRING, group_id STRING, feed_type STRING, description STRING, language STRING, copyright STRING, date_added INT, last_updated INT, image_url STRING, original_document STRING)");
if (queryResponse.Any()) failed.Add("feed_data"); if (queryResponse.Any()) failed.Add("feed");
Log.Verbose("Checking table: {Table}", FeedItemTable); Log.Verbose("Checking table: {Table}", "feed_item");
queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS {FeedItemTable} (id STRING PRIMARY KEY, feed_id STRING, read INT, title STRING, description STRING, link STRING, last_updated INT, publishing_date INT, author STRING, categories STRING, content STRING)"); queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed_item (id STRING PRIMARY KEY, feed_id STRING, read INT, title STRING, description STRING, link STRING, last_updated INT, publishing_date INT, author STRING, categories STRING, content STRING)");
if (queryResponse.Any()) failed.Add("feed_item_data"); if (queryResponse.Any()) failed.Add("feed_item");
if (failed.Any()) if (failed.Any())
{ {

View File

@ -3,9 +3,9 @@ using ToolQit;
namespace SharpRss.Models namespace SharpRss.Models
{ {
public class GroupModel public class CategoryModel
{ {
public GroupModel() public CategoryModel()
{ {
HexColor = Utilities.GenerateRandomHexColor(); HexColor = Utilities.GenerateRandomHexColor();
Id = Guid.NewGuid().ToString(); Id = Guid.NewGuid().ToString();

View File

@ -6,7 +6,9 @@ namespace SharpRss.Models
{ {
public FeedModel? Feed { get; set; } public FeedModel? Feed { get; set; }
public string? Id { get; set; } = string.Empty; public string? Id { get; set; } = string.Empty;
// FeedId will be removed
public string? FeedId { get; set; } = string.Empty; public string? FeedId { get; set; } = string.Empty;
public string FeedUrl { get; set; } = string.Empty;
public bool Read { get; set; } public bool Read { get; set; }
public string? Type { get; set; } = string.Empty; public string? Type { get; set; } = string.Empty;
public string? Title { get; set; } = string.Empty; public string? Title { get; set; } = string.Empty;

View File

@ -7,9 +7,8 @@ namespace SharpRss.Models
public FeedModel(string rssUrl) public FeedModel(string rssUrl)
{ {
Url = rssUrl; Url = rssUrl;
Id = Guid.NewGuid().ToString();
} }
public GroupModel? Group { get; set; } public CategoryModel? Group { get; set; }
public string? Id { get; set; } public string? Id { get; set; }
public string? Url { get; set; } public string? Url { get; set; }
public string? Title { get; set; } = string.Empty; public string? Title { get; set; } = string.Empty;

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Argotic.Common; using Argotic.Common;
using Argotic.Syndication; using Argotic.Syndication;
using Microsoft.Data.Sqlite;
using Serilog; using Serilog;
using SharpRss.Models; using SharpRss.Models;
@ -26,14 +27,50 @@ namespace SharpRss.Services
items.UnionWith(await GetUngroupedFeedsAsync()); items.UnionWith(await GetUngroupedFeedsAsync());
return items; return items;
} }
public async Task<bool> CreateGroupAsync(GroupModel group) => await DbAccess.SetGroupAsync(group); public async Task<bool> CreateGroupAsync(CategoryModel group) => await DbAccess.SetGroupAsync(group);
public async Task<HashSet<GroupModel>> GetGroupsAsync() => await DbAccess.GetGroupsAsync(); public async Task<HashSet<CategoryModel>> GetGroupsAsync() => await DbAccess.GetGroupsAsync();
//TODO: Need to rework this implementation!!! //TODO: Rework this!
public async Task<bool> AddFeedsAsync(string[]? rssUrls, GroupModel? group = null) // Subscribe to a feed.
public async Task<bool> AddSubscriptionAsync(string url, CategoryModel? group = null)
{ {
// Check for valid feed url
bool validate = SyndicationDiscoveryUtility.UriExists(new Uri(url));
if (!validate) return false;
// Check if feed exists in db
FeedModel? dbFeed = await DbAccess.GetFeedAsync(url);
if (dbFeed == null)
{
GenericSyndicationFeed genFeed = new GenericSyndicationFeed();
switch (genFeed.Format)
{
case SyndicationContentFormat.Rss:
RssFeed rssFeed = (RssFeed)genFeed.Resource;
break;
case SyndicationContentFormat.Atom:
AtomFeed atomFeed = (AtomFeed)genFeed.Resource;
break;
default:
Log.Information("Feed implementation missing!");
break;
}
}
// Update feed if newer
// Update/fetch items
return false; return false;
} }
private static FeedModel FromResource(ISyndicationResource resource)
{
FeedModel model = new FeedModel("");
switch (resource)
{
case RssFeed rssFeed:
//TODO: From feed to model
break;
}
return model;
}
public async Task UpdateFeeds() public async Task UpdateFeeds()
{ {
@ -122,14 +159,14 @@ namespace SharpRss.Services
throw; throw;
}*/ }*/
var groups = await GetGroupsAsync(); var groups = await GetGroupsAsync();
GroupModel testGroup = groups.Single(x => x.Name == "News"); CategoryModel testGroup = groups.Single(x => x.Name == "News");
await AddFeedsAsync(new[] /*await AddFeedsAsync(new[]
{ {
"https://www.nu.nl/rss/Algemeen", "https://www.nu.nl/rss/Algemeen",
"https://www.nu.nl/rss/Economie", "https://www.nu.nl/rss/Economie",
"https://www.nu.nl/rss/Sport", "https://www.nu.nl/rss/Sport",
"http://news.google.com/?output=atom" "http://news.google.com/?output=atom"
}, testGroup); }, testGroup);*/
} }
public void Dispose() public void Dispose()

View File

@ -18,12 +18,6 @@ namespace WebSharpRSS
//paths.Set("FaviconResolveUrl", "https://icons.duckduckgo.com/ip3/{0}.ico", false); //paths.Set("FaviconResolveUrl", "https://icons.duckduckgo.com/ip3/{0}.ico", false);
paths.Set("FaviconResolveUrl", "http://www.google.com/s2/favicons?domain={0}", false); paths.Set("FaviconResolveUrl", "http://www.google.com/s2/favicons?domain={0}", false);
paths.Set("LogPath", Path.Combine(Environment.CurrentDirectory, "logs", "log_.json"), false); paths.Set("LogPath", Path.Combine(Environment.CurrentDirectory, "logs", "log_.json"), false);
var dbSql = dataCon["SQL"];
dbSql.Set("Host", "localhost", false);
dbSql.Set("Port", "6969", false);
dbSql.Set("Username", "sharpUser", false);
dbSql.Set("Password", "sh@rP@s$", false);
} }
private static LoggerConfiguration? _configuration; private static LoggerConfiguration? _configuration;

View File

@ -8,7 +8,7 @@ namespace WebSharpRSS.Models
{ {
public class TreeItemData public class TreeItemData
{ {
public TreeItemData(GroupModel groupModel) public TreeItemData(CategoryModel groupModel)
{ {
GroupModel = groupModel; GroupModel = groupModel;
Title = groupModel.Name; Title = groupModel.Name;
@ -23,7 +23,7 @@ namespace WebSharpRSS.Models
if (FeedModel.Url == null) return; if (FeedModel.Url == null) return;
FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), new Uri(FeedModel.Url).Host); FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), new Uri(FeedModel.Url).Host);
} }
public readonly GroupModel? GroupModel; public readonly CategoryModel? GroupModel;
public readonly FeedModel? FeedModel; public readonly FeedModel? FeedModel;
public HashSet<TreeItemData>? Children { get; set; } public HashSet<TreeItemData>? Children { get; set; }

View File

@ -1,12 +0,0 @@
{
"Paths": {
"FaviconResolveUrl": "http://www.google.com/s2/favicons?domain={0}",
"LogPath": "/home/max/GitHub/SharpRSS/WebSharpRSS/logs/log_.json"
},
"SQL": {
"Host": "localhost",
"Port": "6969",
"Username": "sharpUser",
"Password": "sh@rP@s$"
}
}

View File

@ -76,5 +76,5 @@
StateHasChanged(); StateHasChanged();
Log.Verbose("Guide initialized!"); Log.Verbose("Guide initialized!");
} }
private HashSet<TreeItemData> ModelToTreeItem<T>(HashSet<T> model) => model.Select(x => x is GroupModel model ? new TreeItemData(model) : x is FeedModel feedModel ? new TreeItemData(feedModel) : throw new ArgumentException("Item arg is invalid!")).ToHashSet(); private HashSet<TreeItemData> ModelToTreeItem<T>(HashSet<T> model) => model.Select(x => x is CategoryModel model ? new TreeItemData(model) : x is FeedModel feedModel ? new TreeItemData(feedModel) : throw new ArgumentException("Item arg is invalid!")).ToHashSet();
} }