mirror of
https://github.com/hmaxnl/SharpRSS.git
synced 2024-11-09 23:44:20 +01:00
Implementing database backend.
This commit is contained in:
parent
6d2fce5290
commit
367949c200
|
@ -1,30 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace SharpRss.Models
|
namespace SharpRss.Models
|
||||||
{
|
{
|
||||||
public class FeedItemModel
|
public class FeedItemModel
|
||||||
{
|
{
|
||||||
/// <summary>
|
public string Id { get; set; }
|
||||||
/// Last time the item is fetched.
|
|
||||||
/// </summary>
|
|
||||||
public DateTime LastUpdated { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// The feed in which the item is part of.
|
|
||||||
/// </summary>
|
|
||||||
public string FeedId { get; set; }
|
public string FeedId { get; set; }
|
||||||
/// <summary>
|
|
||||||
/// If the item is read.
|
|
||||||
/// </summary>
|
|
||||||
public bool Read { get; set; }
|
public bool Read { get; set; }
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string Link { get; set; }
|
public string Link { get; set; }
|
||||||
public DateTime? PublishingDate { get; set; }
|
public DateTimeOffset LastUpdated { get; set; }
|
||||||
|
public DateTimeOffset? PublishingDate { get; set; }
|
||||||
public string Author { get; set; }
|
public string Author { get; set; }
|
||||||
public string Id { get; set; }
|
|
||||||
public string[] Categories { get; set; }
|
public string[] Categories { get; set; }
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,20 @@ namespace SharpRss.Models
|
||||||
{
|
{
|
||||||
public class FeedModel
|
public class FeedModel
|
||||||
{
|
{
|
||||||
public string FeedId { get; set; }
|
public FeedModel(string rssUrl)
|
||||||
public string GroupId { get; set; }
|
{
|
||||||
public string FeedType { get; set; }
|
Id = Guid.NewGuid().ToString();
|
||||||
public string FeedUrl { get; set; }
|
Url = rssUrl;
|
||||||
public string Description { get; set; }
|
}
|
||||||
public string Language { get; set; }
|
public string Id { get; set; }
|
||||||
public string Copyright { get; set; }
|
public string Url { get; set; }
|
||||||
public DateTime LastUpdated { get; set; }
|
public string? GroupId { get; set; }
|
||||||
public string ImageUrl { get; set; }
|
public string FeedType { get; set; } = string.Empty;
|
||||||
public int TotalItems { get; set; }
|
public string Description { get; set; } = string.Empty;
|
||||||
public int TotalRead { get; set; }
|
public string Language { get; set; } = string.Empty;
|
||||||
|
public string Copyright { get; set; } = string.Empty;
|
||||||
|
public DateTimeOffset DateAdded { get; set; }
|
||||||
|
public DateTimeOffset LastUpdated { get; set; }
|
||||||
|
public string ImageUrl { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,15 @@ namespace SharpRss.Models
|
||||||
{
|
{
|
||||||
public class GroupModel
|
public class GroupModel
|
||||||
{
|
{
|
||||||
public GroupModel(string name)
|
public GroupModel()
|
||||||
{
|
{
|
||||||
Name = name;
|
|
||||||
HexColor = Utilities.GenerateRandomHexColor();
|
HexColor = Utilities.GenerateRandomHexColor();
|
||||||
Id = Guid.NewGuid().ToString();
|
Id = Guid.NewGuid().ToString();
|
||||||
}
|
}
|
||||||
public string Name { get; set; }
|
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
public string HexColor { get; set; }
|
public string HexColor { get; set; }
|
||||||
public string Icon { get; set; }
|
public string Icon { get; set; } = string.Empty;
|
||||||
public string Id { get; private set; }
|
public string Id { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,86 +23,139 @@ namespace SharpRss.Services
|
||||||
private readonly string _feedTable = "feed_data";
|
private readonly string _feedTable = "feed_data";
|
||||||
private readonly string _feedItemTable = "feed_item_data";
|
private readonly string _feedItemTable = "feed_item_data";
|
||||||
|
|
||||||
public async Task RemoveGroupFromFeedsAsync(string groupId)
|
// Group
|
||||||
|
public async Task<HashSet<GroupModel?>> GetGroupsAsync(string? groupName = null)
|
||||||
{
|
{
|
||||||
await _sqlConn.QueryAsync("UPDATE feed_data SET group_id=NULL WHERE group_id=@GroupId", new { GroupId = groupId });
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> AddCategoriesAsync(HashSet<GroupModel> categories)
|
|
||||||
{
|
|
||||||
bool result = true;
|
|
||||||
_sqlConn.Open();
|
_sqlConn.Open();
|
||||||
foreach (var categoryModel in categories)
|
SqliteCommand cmd = new SqliteCommand(groupName != null ? $"SELECT * FROM {_groupTable} WHERE name=@name;" : $"SELECT * FROM {_groupTable}", _sqlConn)
|
||||||
{
|
{
|
||||||
await _sqlConn.QueryAsync("INSERT INTO category_data (name, hex_color, path_icon, category_id) VALUES(@catName, @hexColor, @pathIcon, @categoryId) ON CONFLICT(name) DO UPDATE SET hex_color=@hexColor, path_icon=@pathIcon",
|
Parameters =
|
||||||
new { catName = categoryModel.Name, hexColor = categoryModel.HexColor, pathIcon = categoryModel.Icon, categoryId = categoryModel.Id });
|
|
||||||
}
|
|
||||||
_sqlConn.Close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> AddFeedsAsync(HashSet<FeedModel> feeds)
|
|
||||||
{
|
{
|
||||||
bool result = true;
|
new SqliteParameter("name", groupName)
|
||||||
_sqlConn.Open();
|
|
||||||
foreach (var feedModel in feeds)
|
|
||||||
{
|
|
||||||
await _sqlConn.QueryAsync("INSERT OR REPLACE INTO feed_data(url, feed_id, category_id) VALUES(@url, @feedId, @categoryId) ON CONFLICT(url) DO UPDATE SET category_id=@categoryId", new { url = feedModel.FeedUrl, feedId = feedModel.FeedId, categoryId = feedModel.GroupId });
|
|
||||||
}
|
}
|
||||||
_sqlConn.Close();
|
};
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HashSet<GroupModel>> GetCategoriesAsync()
|
|
||||||
{
|
|
||||||
HashSet<GroupModel> categories = new HashSet<GroupModel>();
|
|
||||||
_sqlConn.Open();
|
|
||||||
SqliteCommand cmd = _sqlConn.CreateCommand();
|
|
||||||
cmd.CommandText = "SELECT * FROM category_data";
|
|
||||||
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
|
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
|
||||||
|
HashSet<GroupModel?> groups = new HashSet<GroupModel?>();
|
||||||
while (reader.Read())
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
//categories.Add(GroupModel.Create(reader["name"].ToString(), reader["hex_color"].ToString(), reader["category_id"].ToString()));
|
groups.Add(new GroupModel()
|
||||||
|
{
|
||||||
|
Name = reader["name"].ToString(),
|
||||||
|
HexColor = reader["hex_color"].ToString(),
|
||||||
|
Icon = reader["icon"].ToString(),
|
||||||
|
Id = reader["id"].ToString()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_sqlConn.Close();
|
_sqlConn.Close();
|
||||||
return categories;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<HashSet<FeedModel>> GetFeedsAsync(string? categoryId = null)
|
/// <summary>
|
||||||
|
/// Creates a group if not exists else will update the group.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="groupModel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<bool> SetGroupAsync(GroupModel groupModel)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
_sqlConn.Open();
|
||||||
|
SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {_groupTable} (id, hex_color, icon, name) VALUES (IFNULL((SELECT id FROM {_groupTable} WHERE name=@name), @id), @hexColor, @icon, @name)", _sqlConn)
|
||||||
|
{
|
||||||
|
Parameters =
|
||||||
|
{
|
||||||
|
new SqliteParameter("id", groupModel.Id),
|
||||||
|
new SqliteParameter("hexColor", groupModel.HexColor),
|
||||||
|
new SqliteParameter("icon", groupModel.Icon),
|
||||||
|
new SqliteParameter("name", groupModel.Name)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int affected = await cmd.ExecuteNonQueryAsync();
|
||||||
|
if (affected != 0)
|
||||||
|
result = true;
|
||||||
|
_sqlConn.Close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> RemoveGroupAsync(GroupModel groupModel)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
_sqlConn.Open();
|
||||||
|
// Remove the group and remove the feeds that were part of the group.
|
||||||
|
SqliteCommand cmd = new SqliteCommand($"DELETE FROM {_groupTable} WHERE id=@id; UPDATE {_feedTable} SET group_id=NULL WHERE group_id=@id", _sqlConn)
|
||||||
|
{
|
||||||
|
Parameters =
|
||||||
|
{
|
||||||
|
new SqliteParameter("id", groupModel.Id)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int affected = await cmd.ExecuteNonQueryAsync();
|
||||||
|
if (affected != 0)
|
||||||
|
result = true;
|
||||||
|
_sqlConn.Close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// Feed
|
||||||
|
public async Task<HashSet<FeedModel>> GetFeedsAsync(string? feedName = null)
|
||||||
{
|
{
|
||||||
HashSet<FeedModel> feeds = new HashSet<FeedModel>();
|
HashSet<FeedModel> feeds = new HashSet<FeedModel>();
|
||||||
_sqlConn.Open();
|
_sqlConn.Open();
|
||||||
|
SqliteCommand cmd = new SqliteCommand(feedName != null ? $"SELECT * FROM {_feedTable} WHERE name=@name" : $"SELECT * FROM {_feedTable}", _sqlConn)
|
||||||
SqliteCommand cmd = _sqlConn.CreateCommand();
|
|
||||||
cmd.CommandText = categoryId == null ? "SELECT * FROM feed_data" : "SELECT * FROM feed_data WHERE category_id=@categoryId";
|
|
||||||
if (categoryId != null)
|
|
||||||
cmd.Parameters.Add(new SqliteParameter("categoryId", categoryId));
|
|
||||||
|
|
||||||
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
{
|
||||||
//feeds.Add(FeedModel.Create(reader["url"].ToString(), reader["feed_id"].ToString(), reader["category_id"].ToString()));
|
Parameters =
|
||||||
|
{
|
||||||
|
new SqliteParameter("name", feedName)
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
int affected = await cmd.ExecuteNonQueryAsync();
|
||||||
|
Log.Verbose("{FeedAmount} feeds found!", affected);
|
||||||
_sqlConn.Close();
|
_sqlConn.Close();
|
||||||
return feeds;
|
return feeds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> AddFeedAsync(FeedModel feedModel)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
_sqlConn.Open();
|
||||||
|
SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {_feedTable} (id, url, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url)" +
|
||||||
|
$"VALUES (IFNULL((SELECT id FROM {_feedTable} WHERE url=@url), @id), @url, @groupId, @feedType, @description, @language, @copyright, @dateAdded, @lastUpdated, @imageUrl)", _sqlConn)
|
||||||
|
{
|
||||||
|
Parameters =
|
||||||
|
{
|
||||||
|
new SqliteParameter("id", feedModel.Id),
|
||||||
|
new SqliteParameter("url", feedModel.Url),
|
||||||
|
new SqliteParameter("groupId", feedModel.GroupId),
|
||||||
|
new SqliteParameter("feedType", feedModel.FeedType),
|
||||||
|
new SqliteParameter("description", feedModel.Description),
|
||||||
|
new SqliteParameter("language", feedModel.Language),
|
||||||
|
new SqliteParameter("copyright", feedModel.Copyright),
|
||||||
|
new SqliteParameter("dateAdded", feedModel.DateAdded.ToUnixTimeMilliseconds()),
|
||||||
|
new SqliteParameter("lastUpdated", feedModel.LastUpdated.ToUnixTimeMilliseconds()),
|
||||||
|
new SqliteParameter("imageUrl", feedModel.ImageUrl)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int affected = await cmd.ExecuteNonQueryAsync();
|
||||||
|
if (affected != 0)
|
||||||
|
result = true;
|
||||||
|
_sqlConn.Close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// Feed item
|
||||||
|
|
||||||
private async void InitializeDb()
|
private async void InitializeDb()
|
||||||
{
|
{
|
||||||
Log.Verbose("Checking database...");
|
Log.Verbose("Checking database...");
|
||||||
HashSet<string> failed = new HashSet<string>();
|
HashSet<string> failed = new HashSet<string>();
|
||||||
_sqlConn.Open();
|
_sqlConn.Open();
|
||||||
Log.Verbose("Checking table: {Table}", _groupTable);
|
Log.Verbose("Checking table: {Table}", _groupTable);
|
||||||
var queryResponse = await _sqlConn.QueryAsync($"CREATE TABLE IF NOT EXISTS {_groupTable} (name STRING NOT NULL, hex_color STRING NOT NULL, icon STRING, id STRING PRIMARY KEY, CONSTRAINT name UNIQUE (name))");
|
var queryResponse = await _sqlConn.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");
|
if (queryResponse.Any()) failed.Add("category_data");
|
||||||
|
|
||||||
Log.Verbose("Checking table: {Table}", _feedTable);
|
Log.Verbose("Checking table: {Table}", _feedTable);
|
||||||
queryResponse = await _sqlConn.QueryAsync($"CREATE TABLE IF NOT EXISTS {_feedTable} (url STRING NOT NULL, id STRING PRIMARY KEY, group_id STRING DEFAULT NULL, CONSTRAINT url, UNIQUE (url))");
|
queryResponse = await _sqlConn.QueryAsync($"CREATE TABLE IF NOT EXISTS {_feedTable} (id STRING PRIMARY KEY, url STRING NOT NULL, group_id STRING DEFAULT NULL, feed_type STRING, description STRING, language STRING, copyright STRING, date_added INT, last_updated INT, image_url STRING)");
|
||||||
if (queryResponse.Any()) failed.Add("feed_data");
|
if (queryResponse.Any()) failed.Add("feed_data");
|
||||||
|
|
||||||
Log.Verbose("Checking table: {Table}", _feedItemTable);
|
Log.Verbose("Checking table: {Table}", _feedItemTable);
|
||||||
queryResponse = await _sqlConn.QueryAsync($"CREATE TABLE IF NOT EXISTS {_feedItemTable} (id STRING PRIMARY KEY, feed_id STRING NOT NULL)");
|
queryResponse = await _sqlConn.QueryAsync($"CREATE TABLE IF NOT EXISTS {_feedItemTable} (id STRING PRIMARY KEY, feed_id STRING DEFAULT NULL, read INT, type STRING, 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_data");
|
||||||
|
|
||||||
_sqlConn.Close();
|
_sqlConn.Close();
|
||||||
|
|
|
@ -15,13 +15,23 @@ namespace SharpRss.Services
|
||||||
{
|
{
|
||||||
public RssService()
|
public RssService()
|
||||||
{
|
{
|
||||||
//SetupTestCategoriesAndFeedsAsync();
|
SetupTestCategoriesAndFeedsAsync();
|
||||||
}
|
}
|
||||||
private readonly DatabaseService _dbService = new DatabaseService();
|
private readonly DatabaseService _dbService = new DatabaseService();
|
||||||
|
|
||||||
/*private async void SetupTestCategoriesAndFeedsAsync()
|
private async void SetupTestCategoriesAndFeedsAsync()
|
||||||
{
|
{
|
||||||
await _dbService.AddCategoriesAsync(new HashSet<CategoryModel>()
|
/*bool result = await _dbService.SetGroupAsync(new GroupModel() { Name = "News" });
|
||||||
|
result = await _dbService.SetGroupAsync(new GroupModel() { Name = "Tech" });
|
||||||
|
result = await _dbService.SetGroupAsync(new GroupModel() { Name = "Science" });
|
||||||
|
result = await _dbService.SetGroupAsync(new GroupModel() { Name = "Test" });*/
|
||||||
|
|
||||||
|
/*GroupModel? editGroup = await _dbService.GetGroupsAsync("Test");
|
||||||
|
if (editGroup != null)
|
||||||
|
{
|
||||||
|
bool result2 = await _dbService.RemoveGroupAsync(editGroup);
|
||||||
|
}*/
|
||||||
|
/*await _dbService.AddCategoriesAsync(new HashSet<CategoryModel>()
|
||||||
{
|
{
|
||||||
new CategoryModel() { Name = "All" },
|
new CategoryModel() { Name = "All" },
|
||||||
new CategoryModel() { Name = "RSS" },
|
new CategoryModel() { Name = "RSS" },
|
||||||
|
@ -34,59 +44,7 @@ namespace SharpRss.Services
|
||||||
new FeedModel("https://www.nasa.gov/rss/dyn/breaking_news.rss"),
|
new FeedModel("https://www.nasa.gov/rss/dyn/breaking_news.rss"),
|
||||||
new FeedModel("https://journals.plos.org/plosone/feed/atom"),
|
new FeedModel("https://journals.plos.org/plosone/feed/atom"),
|
||||||
new FeedModel("https://itsfoss.com/feed")
|
new FeedModel("https://itsfoss.com/feed")
|
||||||
});
|
});*/
|
||||||
}*/
|
|
||||||
|
|
||||||
public async Task<Feed> GetFeedAsync(string rssUrl)
|
|
||||||
{
|
|
||||||
/*return await FeedCache.GetFeed(rssUrl);*/
|
|
||||||
return new Feed();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HashSet<object>> GetAllUnsortedAsync()
|
|
||||||
{
|
|
||||||
HashSet<object> items = new HashSet<object>();
|
|
||||||
/*var categories = await _dbService.GetCategoriesAsync();
|
|
||||||
var feeds = await _dbService.GetFeedsAsync(string.Empty);
|
|
||||||
items.UnionWith(categories);
|
|
||||||
items.UnionWith(feeds);*/
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HashSet<GroupModel>> GetCategoriesAsync()
|
|
||||||
{
|
|
||||||
/*var result = await _dbService.GetCategoriesAsync();
|
|
||||||
return result.OrderBy(x => x.Name).ToHashSet();*/
|
|
||||||
return new HashSet<GroupModel>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HashSet<FeedModel>> GetFeedsAsync(GroupModel? categoryModel = null)
|
|
||||||
{
|
|
||||||
HashSet<FeedModel> feeds = new HashSet<FeedModel>();
|
|
||||||
/*if (categoryModel != null)
|
|
||||||
feeds = await _dbService.GetFeedsAsync(categoryModel.Id);
|
|
||||||
else
|
|
||||||
feeds = await _dbService.GetFeedsAsync();*/
|
|
||||||
return feeds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void AddCategoryAsync(string name, string? icon, string hexColor)
|
|
||||||
{
|
|
||||||
/*GroupModel groupModel = new GroupModel()
|
|
||||||
{
|
|
||||||
Name = name
|
|
||||||
};
|
|
||||||
if (icon != null)
|
|
||||||
groupModel.PathIcon = icon;
|
|
||||||
if (!hexColor.IsNullEmptyWhiteSpace())
|
|
||||||
groupModel.HexColor = hexColor;*/
|
|
||||||
//await _dbService.AddCategoriesAsync(new HashSet<GroupModel>() { groupModel });
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void AddFeedAsync(string rssUrl, GroupModel? category = null)
|
|
||||||
{
|
|
||||||
//FeedModel feedModel = new FeedModel(rssUrl, category);
|
|
||||||
//await _dbService.AddFeedsAsync(new HashSet<FeedModel>() { feedModel });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CodeHollow.FeedReader" Version="1.2.6" />
|
<PackageReference Include="CodeHollow.FeedReader" Version="1.2.6" />
|
||||||
<PackageReference Include="Dapper" Version="2.0.123" />
|
<PackageReference Include="Dapper" Version="2.0.123" />
|
||||||
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="7.0.5" />
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="7.0.5" />
|
||||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user