Working on db backend reimplementing feed adding to db. Reworking UI for reader

This commit is contained in:
Max 2023-05-25 21:51:05 +02:00
parent b0c9816524
commit 842c21c2b9
4 changed files with 69 additions and 44 deletions

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -116,30 +117,35 @@ namespace SharpRss.Services
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
while (reader.Read())
{
feeds.Add(new FeedModel(reader["url"].ToString())
{
Id = reader["id"].ToString(),
Title = reader["title"].ToString(),
GroupId = reader["group_id"].ToString(),
FeedType = reader["feed_type"].ToString(),
Description = reader["description"].ToString(),
Language = reader["language"].ToString(),
Copyright = reader["copyright"].ToString(),
DateAdded = DateTimeOffset.FromUnixTimeMilliseconds(long.TryParse(reader["date_added"].ToString(), out long parsedVal) ? parsedVal : 0),
LastUpdated = DateTimeOffset.FromUnixTimeMilliseconds(long.TryParse(reader["last_updated"].ToString(), out long lastUpdated) ? lastUpdated : 0),
ImageUrl = reader["image_url"].ToString(),
OriginalDocument = reader["original_document"].ToString()
});
feeds.Add(ReaderToFeedModel(reader));
}
_sqlConn.Close();
return feeds;
}
public async Task<bool> SetFeedAsync(FeedModel feedModel)
private FeedModel ReaderToFeedModel(SqliteDataReader reader)
{
bool result = false;
return new FeedModel(reader["url"].ToString())
{
Id = reader["id"].ToString(),
Title = reader["title"].ToString(),
GroupId = reader["group_id"].ToString(),
FeedType = reader["feed_type"].ToString(),
Description = reader["description"].ToString(),
Language = reader["language"].ToString(),
Copyright = reader["copyright"].ToString(),
DateAdded = DateTimeOffset.FromUnixTimeMilliseconds(long.TryParse(reader["date_added"].ToString(), out long parsedVal) ? parsedVal : 0),
LastUpdated = DateTimeOffset.FromUnixTimeMilliseconds(long.TryParse(reader["last_updated"].ToString(), out long lastUpdated) ? lastUpdated : 0),
ImageUrl = reader["image_url"].ToString(),
OriginalDocument = reader["original_document"].ToString()
};
}
public async Task<FeedModel?> SetFeedAsync(FeedModel feedModel)
{
FeedModel? resultModel = null;
_sqlConn.Open();
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 {_feedItemTable} WHERE id=@id), @dateAdded), @lastUpdated, @imageUrl, @originalDoc)", _sqlConn)
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", _sqlConn)
{
Parameters =
{
@ -157,11 +163,11 @@ namespace SharpRss.Services
new SqliteParameter("originalDoc", feedModel.OriginalDocument ?? string.Empty)
}
};
int affected = await cmd.ExecuteNonQueryAsync();
if (affected != 0)
result = true;
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
if (reader.Read())
resultModel = ReaderToFeedModel(reader);
_sqlConn.Close();
return result;
return resultModel;
}
public async Task<bool> RemoveFeedAsync(FeedModel feedModel)
{
@ -183,14 +189,13 @@ namespace SharpRss.Services
// Feed items
public async Task<HashSet<FeedItemModel>> GetFeedItemsAsync(string[]? feedIds = null)
{
List<string>? formattedIds = feedIds?.Select(s => $"'{s}'").ToList();
HashSet<FeedItemModel> feedItems = new HashSet<FeedItemModel>();
_sqlConn.Open();
await using SqliteCommand cmd = new SqliteCommand(
feedIds != null
? $"SELECT * FROM {_feedItemTable} WHERE feed_id IN (@feedIds)"
formattedIds != null
? $"SELECT * FROM {_feedItemTable} WHERE feed_id IN ({string.Join(", ", formattedIds)})"
: $"SELECT * FROM {_feedItemTable}", _sqlConn);
if (feedIds != null)
cmd.Parameters.Add(new SqliteParameter("feedIds", string.Join(',', feedIds)));
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
while (reader.Read())
@ -217,6 +222,7 @@ namespace SharpRss.Services
{
int result = 0;
_sqlConn.Open();
await using SqliteTransaction transaction = _sqlConn.BeginTransaction();
await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {_feedItemTable} (id, feed_id, read, title, description, link, last_updated, publishing_date, author, categories, content)" +
$"VALUES (IFNULL((SELECT id FROM {_feedItemTable} WHERE link=@link), @id), @feedId, @read, @title, @description, @link, @lastUpdated, @publishingDate, @author, @categories, @content)", _sqlConn);
foreach (FeedItemModel item in items)
@ -234,12 +240,15 @@ namespace SharpRss.Services
cmd.Parameters.Add(new SqliteParameter("author", item.Author ?? string.Empty));
cmd.Parameters.Add(new SqliteParameter("categories", item.Categories != null ? string.Join(',', item.Categories) : string.Empty));
cmd.Parameters.Add(new SqliteParameter("content", item.Content ?? string.Empty));
if (_sqlConn.State != ConnectionState.Open)
_sqlConn.Open();
int affected = await cmd.ExecuteNonQueryAsync();
if (affected == 0)
Log.Verbose("Could not set feed item: {FeedLink}", item.Link);
else
result += affected;
}
transaction.Commit();
_sqlConn.Close();
return result; // Return the amount affected rows.
}

View File

@ -16,7 +16,7 @@ namespace SharpRss.Services
{
public RssService()
{
//SetupTestCategoriesAndFeedsAsync();
SetupTestGroupsAndFeedsAsync();
}
private readonly DatabaseService _dbService = new DatabaseService();
@ -50,11 +50,12 @@ namespace SharpRss.Services
ImageUrl = fetched.ImageUrl,
OriginalDocument = fetched.OriginalDocument
};
result = await _dbService.SetFeedAsync(feedModel);
if (!result)
FeedModel? dbFeed = await _dbService.SetFeedAsync(feedModel);
result = dbFeed != null;
if (dbFeed == null)
return result;
if (await AddFeedItems(fetched.Items, feedModel) == 0)
Log.Warning("No feed items added to feed: {FeedUrl}", feedModel.Url);
if (await AddFeedItems(fetched.Items, dbFeed) == 0)
Log.Warning("No feed items added to feed: {FeedUrl}", dbFeed.Url);
return result;
}
public async Task<HashSet<FeedModel>> GetFeedsAsync(string? groupId = null) => await _dbService.GetFeedsAsync(groupId);
@ -106,24 +107,38 @@ namespace SharpRss.Services
}
private async Task<Feed> FetchFeed(string url)
{
Log.Verbose("Fetching feed: {FeedUrl}", url);
var urls = await FeedReader.ParseFeedUrlsAsStringAsync(url);
string feedurl = url;
string feedUrl = url;
if (urls.Any())
feedurl = urls.First();
return await FeedReader.ReadAsync(feedurl);
feedUrl = urls.First();
return await FeedReader.ReadAsync(feedUrl);
}
private async void SetupTestCategoriesAndFeedsAsync()
private async void SetupTestGroupsAndFeedsAsync()
{
var groupRes = await CreateGroupAsync(new GroupModel() { Name = "Test" });
//TODO: Make multiple adding of feed to a transaction, now throws an exception.
/*var groupRes = await CreateGroupAsync(new GroupModel() { Name = "Test" });
groupRes = await CreateGroupAsync(new GroupModel() { Name = "News" });
groupRes = await CreateGroupAsync(new GroupModel() { Name = "Tech" });
groupRes = await CreateGroupAsync(new GroupModel() { Name = "Science" });
var groups = await GetGroupsAsync();
groupRes = await CreateGroupAsync(new GroupModel() { Name = "Science" });*/
/*var groups = await GetGroupsAsync();
GroupModel testGroup = groups.Single(x => x.Name == "Test");
var res = await AddFeed("http://fedoramagazine.org/feed/", testGroup);
res = await AddFeed("https://www.nasa.gov/rss/dyn/breaking_news.rss", testGroup);
res = await AddFeed("https://journals.plos.org/plosone/feed/atom", testGroup);
res = await AddFeed("https://itsfoss.com/feed", testGroup);
await Task.Run(async () =>
{
try
{
var res = await AddFeed("http://fedoramagazine.org/feed/", testGroup);
res = await AddFeed("https://www.nasa.gov/rss/dyn/breaking_news.rss", testGroup);
res = await AddFeed("https://journals.plos.org/plosone/feed/atom", testGroup);
res = await AddFeed("https://itsfoss.com/feed", testGroup);
res = await AddFeed("https://advisories.ncsc.nl/rss/advisories", testGroup);
}
catch (Exception e)
{
Log.Error(e, "Error fetching feeds!");
throw;
}
});*/
}
public void Dispose()

View File

@ -76,12 +76,12 @@
bool faulted = false;
private async void LoadItems()
{
//TODO: better group feed fetching!
faulted = false;
isLoading = true;
if (Fid != null)
{
var fItems = await _rssService.GetFeedItemsAsync(Fid);
items = fItems.Select(x => FeedItemData.FromModel(x)).ToHashSet();
items = fItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet();
isLoading = false;
}
else if (Gid != null)
@ -89,12 +89,13 @@
var feeds = await _rssService.GetFeedsAsync(Gid);
var feedids = feeds.Select(x => x.Id);
var feedItems = await _rssService.GetFeedItemsFromFeedsAsync(feedids.ToArray());
items = feedItems.Select(x => FeedItemData.FromModel(x)).ToHashSet();
items = feedItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet();
}
else
{
faulted = true;
}
isLoading = false;
StateHasChanged();
}
protected override void OnInitialized()

Binary file not shown.