Working on database implementation.

This commit is contained in:
Max 2023-05-18 01:27:11 +02:00
parent c33d8e3a4e
commit 66acd6a1c2
12 changed files with 250 additions and 101 deletions

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using ToolQit.Extensions;
namespace SharpRss.Models
{
@ -7,18 +8,26 @@ namespace SharpRss.Models
/// </summary>
public class CategoryModel
{
public CategoryModel(CategoryModel model)
public CategoryModel()
{
Name = model.Name;
Feeds = model.Feeds;
HexColor = $"#{_random.Next(0x1000000):X6}";
CategoryId = Guid.NewGuid().ToString();
}
public CategoryModel(string name, HashSet<FeedModel> feeds)
private readonly Random _random = new Random();
public static CategoryModel Create(string categoryName, string hexColor, string id)
{
Name = name;
Feeds = feeds;
CategoryModel catModel = new CategoryModel()
{
Name = categoryName,
HexColor = hexColor,
CategoryId = id
};
return catModel;
}
public string Name { get; set; }
public HashSet<FeedModel> Feeds { get; set; }
public string HexColor { get; set; }
public string CategoryId { get; private set; }
}
}

View File

@ -1,20 +1,38 @@
using System.Threading.Tasks;
using System;
using CodeHollow.FeedReader;
namespace SharpRss.Models
{
public class FeedModel
{
public FeedModel(string rssUrl)
private FeedModel()
{
_rssUrl = rssUrl;
_fetchTask = FetchAsync();
}
private readonly Task _fetchTask;
public FeedModel(Feed feed)
{
FeedId = Guid.NewGuid().ToString();
Url = feed.Link;
}
public string Url { get; set; }
public string FeedId { get; private set; }
public string CategoryId { get; set; } = "";
public async Task FetchAsync() => _feed = await FeedCache.GetFeed(_rssUrl);
public static FeedModel Create(string url, string feedId, string categoryId)
{
FeedModel feedModel = new FeedModel()
{
Url = url,
FeedId = feedId,
CategoryId = categoryId
};
return feedModel;
}
private Feed? _feed;
//private readonly Task _fetchTask;
//public async Task FetchAsync() => _feed = await FeedCache.GetFeed(Url);
/*private Feed? _feed;
public Feed Base {
get
{
@ -28,7 +46,6 @@ namespace SharpRss.Models
}
return _feed ?? new Feed();
}
}
private readonly string _rssUrl;
}*/
}
}

View File

@ -1,73 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CodeHollow.FeedReader;
using SharpRss.Models;
namespace SharpRss
{
/// <summary>
/// Managing RSS feeds and categories.
/// </summary>
public class RssService
{
public RssService()
{
/// Storage options:
/// - Database
/// - File
/// - Memory
combined.UnionWith(feedSet);
combined.UnionWith(feedSet2);
}
private static HashSet<FeedModel> feedSet = new HashSet<FeedModel>()
{
new FeedModel("http://fedoramagazine.org/feed/"),
new FeedModel("https://www.nasa.gov/rss/dyn/breaking_news.rss"),
};
private static HashSet<FeedModel> feedSet2 = new HashSet<FeedModel>()
{
new FeedModel("https://journals.plos.org/plosone/feed/atom"),
new FeedModel("https://itsfoss.com/feed")
};
private static HashSet<FeedModel> combined = new HashSet<FeedModel>();
HashSet<CategoryModel> set = new HashSet<CategoryModel>()
{
new CategoryModel("RSS", feedSet),
new CategoryModel("Tech", feedSet2)
};
public async Task<HashSet<CategoryModel>> GetCategories()
{
return set;
}
public async Task<HashSet<FeedModel>> GetAllFeeds()
{
return combined;
}
/// Old
public async Task<Feed> GetFeed(string feedUrl)
{
var urls = await FeedReader.GetFeedUrlsFromUrlAsync(feedUrl);
string url;
if (urls.Count() < 1)
url = _feeds[0];
else
url = urls.First().Url;
return await FeedReader.ReadAsync(url);
}
public async Task<HashSet<Feed>> GetFeedsFromCatAsync(CategoryModel category)
{
return new HashSet<Feed>();
}
private readonly string[] _feeds = { "https://www.reddit.com/r/freshrss/.rss", "http://fedoramagazine.org/" };
}
}

View File

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
using Microsoft.Data.Sqlite;
using Serilog;
using SharpRss.Models;
namespace SharpRss.Services
{
public class DatabaseService : IDisposable
{
private string _connectionString => $"Data Source={Path.Combine(Environment.CurrentDirectory, "sharp_rss.db")};";
internal DatabaseService()
{
_sqlConn = new SqliteConnection(_connectionString);
InitializeDb();
}
private readonly SqliteConnection _sqlConn;
public async Task<bool> AddCategoriesAsync(HashSet<CategoryModel> categories)
{
bool result = true;
_sqlConn.Open();
/*var queryResult = await _sqlConn.QueryAsync("SELECT * FROM category_data WHERE name=@catName", new { catName = category.Name });
var enumerable = queryResult.ToList();
if (queryResult != null && enumerable.Any()) // Category already exists!
result = false;*/
foreach (var categoryModel in categories)
{
await _sqlConn.QueryAsync("INSERT OR IGNORE INTO category_data (name, hex_color, category_id) VALUES(@catName, @hexColor, @categoryId)",
new { catName = categoryModel.Name, hexColor = categoryModel.HexColor, categoryId = categoryModel.CategoryId });
}
/*if (result)
{
if (createResult.Any()) // Did not create the category
result = false;
}*/
_sqlConn.Close();
return result;
}
public async Task<bool> AddFeedsAsync(HashSet<FeedModel> feeds)
{
bool result = true;
_sqlConn.Open();
foreach (var feedModel in feeds)
{
await _sqlConn.QueryAsync("INSERT OR IGNORE INTO feed_data(url, feed_id, category_id) VALUES(@url, @feedId, @categoryId)", new { url = feedModel.Url, feedId = feedModel.FeedId, categoryId = feedModel.CategoryId });
}
_sqlConn.Close();
return result;
}
public async Task<HashSet<CategoryModel>> GetCategoriesAsync()
{
HashSet<CategoryModel> categories = new HashSet<CategoryModel>();
_sqlConn.Open();
SqliteCommand cmd = _sqlConn.CreateCommand();
cmd.CommandText = "SELECT * FROM category_data";
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
while (reader.Read())
categories.Add(CategoryModel.Create(reader["name"].ToString(), reader["hex_color"].ToString(), reader["category_id"].ToString()));
_sqlConn.Close();
return categories;
}
public async Task<HashSet<FeedModel>> GetFeedsAsync(string? categoryId = null)
{
HashSet<FeedModel> feeds = new HashSet<FeedModel>();
_sqlConn.Open();
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()));
_sqlConn.Close();
return feeds;
}
private async void InitializeDb()
{
Log.Verbose("Checking database...");
_sqlConn.Open();
var queryResponse = await _sqlConn.QueryAsync("CREATE TABLE IF NOT EXISTS category_data (name STRING NOT NULL, hex_color STRING NOT NULL, category_id STRING PRIMARY KEY)");
if (queryResponse.Any())
{
_sqlConn.Close();
_sqlConn.Dispose();
throw new SqliteException("Error initializing database!", 0);
}
queryResponse = await _sqlConn.QueryAsync("CREATE TABLE IF NOT EXISTS feed_data (url STRING NOT NULL, feed_id STRING PRIMARY KEY, category_id STRING DEFAULT '')");
if (queryResponse.Any())
{
_sqlConn.Close();
_sqlConn.Dispose();
throw new SqliteException("Error initializing database!", 0);
}
_sqlConn.Close();
Log.Verbose("Checking database done!");
}
public void Dispose()
{
_sqlConn.Dispose();
}
}
}

View File

@ -0,0 +1,74 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using SharpRss.Models;
namespace SharpRss.Services
{
/// <summary>
/// Managing RSS feeds and categories.
/// </summary>
public class RssService
{
public RssService()
{
_dbService = new DatabaseService();
Initialize();
}
private readonly DatabaseService _dbService;
private async void Initialize()
{
//HashSet<CategoryModel> categoryModels = await _dbService.GetCategoriesAsync();
}
public async Task<HashSet<object>> GetAllAsync()
{
HashSet<object> items = new HashSet<object>();
return items;
}
public async Task<HashSet<CategoryModel>> GetCategoriesAsync()
{
return new HashSet<CategoryModel>();
}
public async Task<HashSet<FeedModel>> GetFeedsAsync(CategoryModel? categoryModel = null)
{
HashSet<FeedModel> feeds = new HashSet<FeedModel>();
if (categoryModel != null)
{
// Get feeds from the category.
}
else
{
// Get all the feeds.
}
return feeds;
}
public async void AddCategoryAsync(string name)
{
}
public async void AddFeedAsync(string rssUrl)
{
}
/*private static HashSet<FeedModel> feedSet = new HashSet<FeedModel>()
{
new FeedModel("http://fedoramagazine.org/feed/"),
new FeedModel("https://www.nasa.gov/rss/dyn/breaking_news.rss"),
};
private static HashSet<FeedModel> feedSet2 = new HashSet<FeedModel>()
{
new FeedModel("https://journals.plos.org/plosone/feed/atom"),
new FeedModel("https://itsfoss.com/feed")
};*/
/*HashSet<CategoryModel> set = new HashSet<CategoryModel>()
{
new CategoryModel("RSS", feedSet),
new CategoryModel("Tech", feedSet2)
};*/
}
}

View File

@ -9,6 +9,8 @@
<ItemGroup>
<PackageReference Include="CodeHollow.FeedReader" Version="1.2.6" />
<PackageReference Include="Dapper" Version="2.0.123" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="7.0.5" />
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
</ItemGroup>

View File

@ -1,4 +1,6 @@
using SharpRss.Models;
using System;
using System.Collections.Generic;
using SharpRss.Models;
namespace WebSharpRSS.Models
{

View File

@ -13,7 +13,7 @@ namespace WebSharpRSS.Models
public TreeItemData(CategoryModel catModel)
{
CategoryModel = catModel;
Feeds = CategoryModel.Feeds.Where(x => x.Base != null).Select(x => new TreeItemData(x)).ToHashSet();
//Feeds = CategoryModel.Feeds.Where(x => x.Base != null).Select(x => new TreeItemData(x)).ToHashSet();
Title = CategoryModel.Name;
Icon = Icons.Material.Filled.RssFeed;
}
@ -21,7 +21,7 @@ namespace WebSharpRSS.Models
public TreeItemData(FeedModel feedModel)
{
FeedModel = feedModel;
Feed = FeedModel.Base;
//Feed = FeedModel.Base;
Title = Feed.Title;
string faviconAddress = Feed.Link.Remove(Feed.Link.IndexOf("http", StringComparison.Ordinal), Feed.Link.IndexOf("://", StringComparison.Ordinal) + 3);
FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), faviconAddress);

View File

@ -2,6 +2,7 @@
@using CodeHollow.FeedReader;
@using SharpRss.Models;
@using WebSharpRSS.Models;
@using SharpRss.Services
@inject RssService _rssService;
@inject FeedStateContainer _stateContainer;
@ -11,12 +12,12 @@
{
foreach (var feedItem in _items)
{
<MudItem>
<MudItem xs="6">
<MudCard>
<MudCardContent>
<MudText>@feedItem.Title</MudText>
<MudText Typo="Typo.body2">@feedItem.Description</MudText>
<MudText Typo="Typo.overline">@feedItem.PublishingDateString</MudText>
<MudText Typo="Typo.overline">@feedItem.PublishingDate.ToString()</MudText>
</MudCardContent>
</MudCard>
</MudItem>
@ -46,7 +47,7 @@
if (Feeds == null) return;
foreach (var feedmodel in Feeds)
{
_items = feedmodel.Base.Items.OrderBy(x => x.PublishingDate).ToHashSet();
//_items = feedmodel.Base.Items.OrderBy(x => x.PublishingDate).Reverse().ToHashSet();
}
}
}

View File

@ -6,6 +6,7 @@ using MudBlazor.Services;
using Serilog;
using SharpRss;
using SharpRss.Models;
using SharpRss.Services;
using ToolQit;
using WebSharpRSS;
using WebSharpRSS.Models;

View File

@ -2,6 +2,7 @@
@using MudBlazor.Utilities
@using CodeHollow.FeedReader
@using Serilog
@using SharpRss.Services
@using WebSharpRSS.Models;
@using ToolQit.Extensions;
@ -10,7 +11,7 @@
@inject RssService _rssService
<MudStack Spacing="2">
<MudTreeView Items="Categories" @bind-SelectedValue="SelectedItem" Hover="true">
<MudTreeView Items="GuideItems" @bind-SelectedValue="SelectedItem" Hover="true">
<ItemTemplate>
<MudTreeViewItem @bind-Expanded="@context.IsExpanded" Items="@context.Feeds" Value="@context">
<Content>
@ -38,7 +39,7 @@
</MudStack>
@code {
public HashSet<TreeItemData> Categories = new HashSet<TreeItemData>();
public HashSet<TreeItemData> GuideItems = new HashSet<TreeItemData>();
private TreeItemData? _selecteditem;
private TreeItemData? SelectedItem
{
@ -58,14 +59,13 @@
{
}
//_navManager.NavigateTo("/");
}
protected override async void OnInitialized()
{
Log.Verbose("Loading guide data...");
HashSet<CategoryModel> cats = await _rssService.GetCategories();
await Task.Run(() => Categories.UnionWith(cats.Select(x => new TreeItemData(x)).ToHashSet()));
/*HashSet<CategoryModel> cats = await _rssService.GetAllAsync();
await Task.Run(() => Categories.UnionWith(cats.Select(x => new TreeItemData(x)).ToHashSet()));*/
StateHasChanged();
Log.Verbose(" Guide initialized!");

BIN
WebSharpRSS/sharp_rss.db Normal file

Binary file not shown.