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";
// 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);
dbc.Open();
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();
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);
while (reader.Read())
{
@ -43,7 +42,7 @@ namespace SharpRss
using SqliteDataReader countReader = await cmdFeedCount.ExecuteReaderAsync();
int count = countReader.Read() ? countReader.GetInt32(0) : 0;
groups.Add(new GroupModel()
groups.Add(new CategoryModel()
{
Name = reader["name"].ToString(),
FeedCount = count,
@ -54,7 +53,7 @@ namespace SharpRss
}
return groups;
}
public static async Task<bool> SetGroupAsync(GroupModel groupModel)
public static async Task<bool> SetGroupAsync(CategoryModel groupModel)
{
bool result = false;
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
@ -74,7 +73,7 @@ namespace SharpRss
result = true;
return result;
}
public static async Task<bool> RemoveGroupAsync(GroupModel groupModel)
public static async Task<bool> RemoveGroupAsync(CategoryModel groupModel)
{
bool result = false;
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
@ -93,6 +92,7 @@ namespace SharpRss
return result;
}
// Feeds
/// <summary>
///
/// </summary>
@ -115,14 +115,15 @@ namespace SharpRss
feeds.Add(await ReaderToFeedModel(reader));
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);
dbc.Open();
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();
if (reader.Read())
@ -241,7 +242,7 @@ namespace SharpRss
};
if (feedItemModel is { FeedId: { } })
{
FeedModel? feedModel = await GetFeedAsync(feedItemModel.FeedId);
FeedModel? feedModel = await GetFeedAsync(feedItemModel.FeedUrl);
feedItemModel.Feed = feedModel;
}
feedItems.Add(feedItemModel);
@ -303,9 +304,9 @@ namespace SharpRss
result = true;
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);
dbc.Open();
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();
HashSet<GroupModel>? groups = null;
HashSet<CategoryModel>? groups = null;
if (reader.Read())
groups = await GetGroupsAsync(reader["group_id"].ToString());
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()
{
if (_isInitialized) return;
@ -359,17 +356,17 @@ namespace SharpRss
HashSet<string> failed = new HashSet<string>();
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
dbc.Open();
Log.Verbose("Checking table: {Table}", GroupTable);
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)");
if (queryResponse.Any()) failed.Add("category_data");
Log.Verbose("Checking table: {Table}", "category");
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");
Log.Verbose("Checking table: {Table}", FeedTable);
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)");
if (queryResponse.Any()) failed.Add("feed_data");
Log.Verbose("Checking table: {Table}", "feed");
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");
Log.Verbose("Checking table: {Table}", FeedItemTable);
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)");
if (queryResponse.Any()) failed.Add("feed_item_data");
Log.Verbose("Checking table: {Table}", "feed_item");
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");
if (failed.Any())
{

View File

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

View File

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

View File

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

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Argotic.Common;
using Argotic.Syndication;
using Microsoft.Data.Sqlite;
using Serilog;
using SharpRss.Models;
@ -26,14 +27,50 @@ namespace SharpRss.Services
items.UnionWith(await GetUngroupedFeedsAsync());
return items;
}
public async Task<bool> CreateGroupAsync(GroupModel group) => await DbAccess.SetGroupAsync(group);
public async Task<HashSet<GroupModel>> GetGroupsAsync() => await DbAccess.GetGroupsAsync();
public async Task<bool> CreateGroupAsync(CategoryModel group) => await DbAccess.SetGroupAsync(group);
public async Task<HashSet<CategoryModel>> GetGroupsAsync() => await DbAccess.GetGroupsAsync();
//TODO: Need to rework this implementation!!!
public async Task<bool> AddFeedsAsync(string[]? rssUrls, GroupModel? group = null)
//TODO: Rework this!
// 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;
}
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()
{
@ -122,14 +159,14 @@ namespace SharpRss.Services
throw;
}*/
var groups = await GetGroupsAsync();
GroupModel testGroup = groups.Single(x => x.Name == "News");
await AddFeedsAsync(new[]
CategoryModel testGroup = groups.Single(x => x.Name == "News");
/*await AddFeedsAsync(new[]
{
"https://www.nu.nl/rss/Algemeen",
"https://www.nu.nl/rss/Economie",
"https://www.nu.nl/rss/Sport",
"http://news.google.com/?output=atom"
}, testGroup);
}, testGroup);*/
}
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", "http://www.google.com/s2/favicons?domain={0}", 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;

View File

@ -8,7 +8,7 @@ namespace WebSharpRSS.Models
{
public class TreeItemData
{
public TreeItemData(GroupModel groupModel)
public TreeItemData(CategoryModel groupModel)
{
GroupModel = groupModel;
Title = groupModel.Name;
@ -23,7 +23,7 @@ namespace WebSharpRSS.Models
if (FeedModel.Url == null) return;
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 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();
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();
}