diff --git a/SharpRss/DbAccess.cs b/SharpRss/DbAccess.cs index f578d9a..2bb740f 100644 --- a/SharpRss/DbAccess.cs +++ b/SharpRss/DbAccess.cs @@ -4,6 +4,7 @@ using System.Data; using System.IO; using System.Linq; using System.Threading.Tasks; +using System.Transactions; using Argotic.Syndication; using Dapper; using Microsoft.Data.Sqlite; @@ -42,7 +43,7 @@ namespace SharpRss using SqliteDataReader countReader = await cmdFeedCount.ExecuteReaderAsync(); int count = countReader.Read() ? countReader.GetInt32(0) : 0; - groups.Add(new CategoryModel() + groups.Add(new CategoryModel() { Name = reader["name"].ToString(), FeedCount = count, @@ -78,7 +79,7 @@ namespace SharpRss bool result = false; await using SqliteConnection dbc = new SqliteConnection(ConnectionString); dbc.Open(); - // Remove the group and remove the feeds that were part of the group. + // Remove the group and remove the feeds that were part of the group. await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {GroupTable} WHERE id=@id; UPDATE {FeedTable} SET group_id=NULL WHERE group_id=@id", dbc) { Parameters = @@ -125,45 +126,86 @@ namespace SharpRss { Parameters = { new SqliteParameter("Url", url) } }; - await using SqliteDataReader reader = await cmd.ExecuteReaderAsync(); - if (reader.Read()) - feed = await ReaderToFeedModel(reader); + try + { + await using SqliteDataReader reader = await cmd.ExecuteReaderAsync(); + if (reader.Read()) + feed = await ReaderToFeedModel(reader); + } + catch (Exception ex) + { + Log.Error(ex, "Error while fetching feed from db."); + } return feed; } - public static async Task SetFeedsAsync(IEnumerable feedModels) + public static async Task SetFeedAsync(FeedModel feedModel) { - //TODO: Implement fetching system!!! - FeedModel? resultModel = null; + FeedModel? feed = null; await using SqliteConnection dbc = new SqliteConnection(ConnectionString); dbc.Open(); - await using SqliteTransaction transaction = dbc.BeginTransaction(); - foreach (var feedModel in feedModels) + await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedTable} (url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (@url, @title, @groupId, @feedType, @description, @language, @copyright, @dateAdded), @lastUpdated, @imageUrl, @originalDoc); SELECT * FROM {FeedTable} WHERE url=@url", dbc) { - //await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {_feedTable} (id, url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (IFNULL((SELECT id FROM {_feedTable} WHERE url=@url), @id), @url, @title, @groupId, @feedType, @description, @language, @copyright, IFNULL((SELECT date_added FROM {_feedTable} WHERE id=@id), @dateAdded), @lastUpdated, @imageUrl, @originalDoc); SELECT * FROM {_feedTable} WHERE url=@url", dbc) - await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedTable} (id, url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (IFNULL((SELECT id FROM {FeedTable} WHERE url=@url), @id), @url, @title, @groupId, @feedType, @description, @language, @copyright, IFNULL((SELECT date_added FROM {FeedTable} WHERE id=@id), @dateAdded), @lastUpdated, @imageUrl, @originalDoc)", dbc) + Parameters = { - Parameters = - { - new SqliteParameter("id", feedModel.Id ?? string.Empty), - new SqliteParameter("url", feedModel.Url ?? string.Empty), - new SqliteParameter("title", feedModel.Title ?? string.Empty), - new SqliteParameter("groupId", feedModel.GroupId ?? string.Empty), - new SqliteParameter("feedType", feedModel.FeedType ?? string.Empty), - new SqliteParameter("description", feedModel.Description ?? string.Empty), - new SqliteParameter("language", feedModel.Language ?? string.Empty), - new SqliteParameter("copyright", feedModel.Copyright ?? string.Empty), - new SqliteParameter("dateAdded", feedModel.DateAdded?.ToUnixTimeMilliseconds()), - new SqliteParameter("lastUpdated", feedModel.LastUpdated?.ToUnixTimeMilliseconds()), - new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty), - new SqliteParameter("originalDoc", feedModel.OriginalDocument ?? string.Empty) - }, - Transaction = transaction - }; - await cmd.ExecuteNonQueryAsync(); + new SqliteParameter("url", feedModel.Url ?? string.Empty), + new SqliteParameter("title", feedModel.Title ?? string.Empty), + new SqliteParameter("groupId", feedModel.GroupId ?? string.Empty), + new SqliteParameter("feedType", feedModel.FeedType ?? string.Empty), + new SqliteParameter("description", feedModel.Description ?? string.Empty), + new SqliteParameter("language", feedModel.Language ?? string.Empty), + new SqliteParameter("copyright", feedModel.Copyright ?? string.Empty), + new SqliteParameter("dateAdded", feedModel.DateAdded?.ToUnixTimeMilliseconds()), + new SqliteParameter("lastUpdated", feedModel.LastUpdated?.ToUnixTimeMilliseconds()), + new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty), + new SqliteParameter("originalDoc", feedModel.OriginalDocument ?? string.Empty) + } + }; + try + { + await using SqliteDataReader reader = await cmd.ExecuteReaderAsync(); + feed = await ReaderToFeedModel(reader); } - await transaction.CommitAsync(); - await FetchFeedItemsAsync(feedModels.Select(x => x.Url).ToArray()); - return resultModel; + catch (Exception ex) + { + Log.Error(ex, "Database error, adding feed model to database failed!"); + return feed; + } + return feed; + /*await using SqliteTransaction transaction = dbc.BeginTransaction(); + try + { + foreach (var feedModel in feedModels) + { + //await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {_feedTable} (id, url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (IFNULL((SELECT id FROM {_feedTable} WHERE url=@url), @id), @url, @title, @groupId, @feedType, @description, @language, @copyright, IFNULL((SELECT date_added FROM {_feedTable} WHERE id=@id), @dateAdded), @lastUpdated, @imageUrl, @originalDoc); SELECT * FROM {_feedTable} WHERE url=@url", dbc) + await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedTable} (id, url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (IFNULL((SELECT id FROM {FeedTable} WHERE url=@url), @id), @url, @title, @groupId, @feedType, @description, @language, @copyright, IFNULL((SELECT date_added FROM {FeedTable} WHERE id=@id), @dateAdded), @lastUpdated, @imageUrl, @originalDoc)", dbc) + { + Parameters = + { + new SqliteParameter("id", feedModel.Id ?? string.Empty), + new SqliteParameter("url", feedModel.Url ?? string.Empty), + new SqliteParameter("title", feedModel.Title ?? string.Empty), + new SqliteParameter("groupId", feedModel.GroupId ?? string.Empty), + new SqliteParameter("feedType", feedModel.FeedType ?? string.Empty), + new SqliteParameter("description", feedModel.Description ?? string.Empty), + new SqliteParameter("language", feedModel.Language ?? string.Empty), + new SqliteParameter("copyright", feedModel.Copyright ?? string.Empty), + new SqliteParameter("dateAdded", feedModel.DateAdded?.ToUnixTimeMilliseconds()), + new SqliteParameter("lastUpdated", feedModel.LastUpdated?.ToUnixTimeMilliseconds()), + new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty), + new SqliteParameter("originalDoc", feedModel.OriginalDocument ?? string.Empty) + }, + Transaction = transaction + }; + await cmd.ExecuteNonQueryAsync(); + } + await transaction.CommitAsync(); + } + catch (Exception ex) + { + await transaction.RollbackAsync(); + Log.Error(ex, "Error on inserting feeds to db."); + return false; + }*/ } public static async Task FetchFeedItemsAsync(string[]? feedUrls = null) @@ -188,8 +230,8 @@ namespace SharpRss { GenericSyndicationFeed syndication = new GenericSyndicationFeed(); syndication.Load(dbFeed.OriginalDocument); + //TODO: Get items and add to db } - //TODO: Rewrite some stuff... } public static async Task RemoveFeedAsync(FeedModel feedModel) @@ -197,11 +239,11 @@ namespace SharpRss bool result = false; await using SqliteConnection dbc = new SqliteConnection(ConnectionString); dbc.Open(); - await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {FeedTable} WHERE id=@id; UPDATE {FeedItemTable} SET feed_id=NULL WHERE feed_id=@id", dbc) + await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {FeedTable} WHERE url=@Url; UPDATE {FeedItemTable} SET feed_id=NULL WHERE feed_id=@Url", dbc) { Parameters = { - new SqliteParameter("id", feedModel.Id) + new SqliteParameter("Url", feedModel.Url) } }; int affected = await cmd.ExecuteNonQueryAsync(); @@ -280,10 +322,10 @@ namespace SharpRss dbc.Open(); int affected = await cmd.ExecuteNonQueryAsync(); if (affected == 0) - Log.Verbose("Could not set feed item: {FeedLink}", item.Link); + Log.Verbose("Could not set feed item: {FeedLink}", item.Link); else - result += affected; - } + result += affected; + } transaction.Commit(); return result; } @@ -326,9 +368,9 @@ namespace SharpRss } private static async Task ReaderToFeedModel(SqliteDataReader reader) { - FeedModel fetchedFeed = new FeedModel(reader["url"].ToString()) + FeedModel fetchedFeed = new FeedModel() { - Id = reader["id"].ToString(), + Url = reader["url"].ToString(), Title = reader["title"].ToString(), GroupId = reader["group_id"].ToString(), FeedType = reader["feed_type"].ToString(), @@ -340,14 +382,15 @@ namespace SharpRss ImageUrl = reader["image_url"].ToString(), OriginalDocument = reader["original_document"].ToString() }; - var groupFetch = await GetGroupsAsync(fetchedFeed.GroupId); + //TODO: Set group on insert + /*var groupFetch = await GetGroupsAsync(fetchedFeed.GroupId); if (groupFetch.Any()) fetchedFeed.Group = groupFetch.First(); else - Log.Warning("Could not get group from feed: {FeedId}", fetchedFeed.Id); + Log.Warning("Could not get group from feed: {FeedId}", fetchedFeed.Id);*/ return fetchedFeed; } - + //=== public static async void Initialize() { @@ -359,7 +402,7 @@ namespace SharpRss 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}", "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"); @@ -367,7 +410,7 @@ namespace SharpRss 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()) { var joined = string.Join(',', failed); diff --git a/SharpRss/Models/FeedModel.cs b/SharpRss/Models/FeedModel.cs index 8fdb172..5f2b50a 100644 --- a/SharpRss/Models/FeedModel.cs +++ b/SharpRss/Models/FeedModel.cs @@ -4,13 +4,11 @@ namespace SharpRss.Models { public class FeedModel { - public FeedModel(string rssUrl) + public FeedModel() { - Url = rssUrl; } public CategoryModel? Group { 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? GroupId { get; set; } = string.Empty; public string? FeedType { get; set; } = string.Empty; diff --git a/SharpRss/Services/RssService.cs b/SharpRss/Services/RssService.cs index ce7a7d9..115fe72 100644 --- a/SharpRss/Services/RssService.cs +++ b/SharpRss/Services/RssService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.Design; using System.Linq; using System.Threading.Tasks; using Argotic.Common; @@ -38,35 +39,33 @@ namespace SharpRss.Services 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) + FeedModel? fModel = await DbAccess.GetFeedAsync(url); + // If not exists fetch feed & add. + if (fModel == 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; - } + GenericSyndicationFeed genFeed = GenericSyndicationFeed.Create(new Uri(url)); + fModel = FromResource(genFeed.Resource); + fModel.GroupId = group?.Id; + // Add feed + FeedModel? dbFeed = await DbAccess.SetFeedAsync(fModel); + // Update/fetch items + await DbAccess.FetchFeedItemsAsync(new string[] { fModel.Url }); } - // Update feed if newer - // Update/fetch items - return false; } private static FeedModel FromResource(ISyndicationResource resource) { - FeedModel model = new FeedModel(""); - switch (resource) + FeedModel model = new FeedModel(); + switch (resource.Format) { - case RssFeed rssFeed: - //TODO: From feed to model + case SyndicationContentFormat.Rss: + RssFeed rssFeed = (RssFeed)resource; + break; + case SyndicationContentFormat.Atom: + AtomFeed atomFeed = (AtomFeed)resource; + break; + default: + Log.Information("Feed implementation missing!"); break; } return model; @@ -158,8 +157,9 @@ namespace SharpRss.Services Log.Error(e, "Error fetching feeds!"); throw; }*/ - var groups = await GetGroupsAsync(); - CategoryModel testGroup = groups.Single(x => x.Name == "News"); + /*var groups = await GetGroupsAsync(); + CategoryModel testGroup = groups.Single(x => x.Name == "News");*/ + await AddSubscriptionAsync("https://www.nu.nl/rss/Algemeen"); /*await AddFeedsAsync(new[] { "https://www.nu.nl/rss/Algemeen", diff --git a/WebSharpRSS/Pages/List.razor b/WebSharpRSS/Pages/List.razor index 1456eda..1037a23 100644 --- a/WebSharpRSS/Pages/List.razor +++ b/WebSharpRSS/Pages/List.razor @@ -57,7 +57,7 @@ else if (Gid != null) { var feeds = await _rssService.GetFeedsAsync(Gid); - var feedIds = feeds.Select(x => x.Id); + var feedIds = feeds.Select(x => x.Url); var feedItems = await _rssService.GetFeedItemsFromFeedsAsync(feedIds.ToArray()); items = feedItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet(); } diff --git a/WebSharpRSS/Shared/SideGuide.razor b/WebSharpRSS/Shared/SideGuide.razor index 0f2ec49..fa1dc59 100644 --- a/WebSharpRSS/Shared/SideGuide.razor +++ b/WebSharpRSS/Shared/SideGuide.razor @@ -51,7 +51,7 @@ if (_selectedItem == null) return; if (_selectedItem.FeedModel != null) { - _navigation.NavigateTo($"/list?fid={_selectedItem.FeedModel.Id}"); + _navigation.NavigateTo($"/list?fid={_selectedItem.FeedModel.Url}"); } else if (_selectedItem.GroupModel != null) { diff --git a/WebSharpRSS/sharp_rss.sqlite b/WebSharpRSS/sharp_rss.sqlite index 40e2446..c7ccdf9 100644 Binary files a/WebSharpRSS/sharp_rss.sqlite and b/WebSharpRSS/sharp_rss.sqlite differ