Reworking models.

This commit is contained in:
Max 2023-05-20 00:04:45 +02:00
parent 43cb208910
commit e4a0f4ce7d
14 changed files with 103 additions and 124 deletions

View File

@ -1,33 +0,0 @@
using System;
namespace SharpRss.Models
{
/// <summary>
/// To store and load data from file/database
/// </summary>
public class CategoryModel
{
public CategoryModel()
{
HexColor = $"#{_random.Next(0x1000000):X6}";
CategoryId = Guid.NewGuid().ToString();
}
private readonly Random _random = new Random();
public static CategoryModel Create(string categoryName, string hexColor, string id)
{
CategoryModel catModel = new CategoryModel()
{
Name = categoryName,
HexColor = hexColor,
CategoryId = id
};
return catModel;
}
public string Name { get; set; }
public string HexColor { get; set; }
public string PathIcon { get; set; }
public string CategoryId { get; private set; }
}
}

View File

@ -11,14 +11,13 @@ namespace SharpRss.Models
/// </summary> /// </summary>
public DateTime LastUpdated { get; set; } public DateTime LastUpdated { get; set; }
/// <summary> /// <summary>
/// The feed in which the item is part. /// The feed in which the item is part of.
/// </summary> /// </summary>
public string FeedId { get; set; } public string FeedId { get; set; }
/// <summary> /// <summary>
/// If the item is read. /// If the item is read.
/// </summary> /// </summary>
public string 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; }

View File

@ -5,37 +5,14 @@ namespace SharpRss.Models
{ {
public class FeedModel public class FeedModel
{ {
private FeedModel() public string FeedId { get; set; }
{ public string CategoryId { get; set; }
public string FeedType { get; set; }
}
public FeedModel(string rssFeedUrl, CategoryModel? category = null)
{
if (category != null)
CategoryId = category.CategoryId;
FeedId = Guid.NewGuid().ToString();
FeedUrl = rssFeedUrl;
}
public string FeedId { get; private set; }
public string CategoryId { get; set; } = "";
public string FeedType { get; set; }
public string FeedUrl { get; set; } public string FeedUrl { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string Language { get; set; } public string Language { get; set; }
public string Copyright { get; set; } public string Copyright { get; set; }
public DateTime LastUpdated { get; set; } public DateTime LastUpdated { get; set; }
public string ImageUrl { get; set; } public string ImageUrl { get; set; }
public static FeedModel Create(string url, string feedId, string categoryId)
{
FeedModel feedModel = new FeedModel()
{
FeedUrl = url,
FeedId = feedId,
CategoryId = categoryId
};
return feedModel;
}
} }
} }

View File

@ -0,0 +1,22 @@
using System;
namespace SharpRss.Models
{
/// <summary>
/// To store and load data from file/database
/// </summary>
public class GroupModel
{
/*public GroupModel()
{
HexColor = $"#{_random.Next(0x1000000):X6}";
Id = Guid.NewGuid().ToString();
}
private readonly Random _random = new Random();*/
public string Name { get; set; }
public string HexColor { get; set; }
public string Icon { get; set; }
public string Id { get; private set; }
}
}

View File

@ -2,7 +2,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dapper; using Dapper;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
@ -13,22 +12,30 @@ namespace SharpRss.Services
{ {
internal class DatabaseService : IDisposable internal class DatabaseService : IDisposable
{ {
private string _connectionString => $"Data Source={Path.Combine(Environment.CurrentDirectory, "sharp_rss.db")};";
internal DatabaseService() internal DatabaseService()
{ {
_sqlConn = new SqliteConnection(_connectionString); _sqlConn = new SqliteConnection(_connectionString);
InitializeDb(); InitializeDb();
} }
private readonly SqliteConnection _sqlConn; private readonly SqliteConnection _sqlConn;
private readonly string _connectionString = $"Data Source={Path.Combine(Environment.CurrentDirectory, "sharp_rss.sqlite")};";
private readonly string _groupTable = "group_data";
private readonly string _feedTable = "feed_data";
private readonly string _feedItemTable = "feed_item_data";
public async Task<bool> AddCategoriesAsync(HashSet<CategoryModel> categories) public async Task RemoveGroupFromFeedsAsync(string groupId)
{
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; bool result = true;
_sqlConn.Open(); _sqlConn.Open();
foreach (var categoryModel in categories) foreach (var categoryModel in categories)
{ {
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", 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",
new { catName = categoryModel.Name, hexColor = categoryModel.HexColor, pathIcon = categoryModel.PathIcon, categoryId = categoryModel.CategoryId }); new { catName = categoryModel.Name, hexColor = categoryModel.HexColor, pathIcon = categoryModel.Icon, categoryId = categoryModel.Id });
} }
_sqlConn.Close(); _sqlConn.Close();
return result; return result;
@ -46,15 +53,18 @@ namespace SharpRss.Services
return result; return result;
} }
public async Task<HashSet<CategoryModel>> GetCategoriesAsync() public async Task<HashSet<GroupModel>> GetCategoriesAsync()
{ {
HashSet<CategoryModel> categories = new HashSet<CategoryModel>(); HashSet<GroupModel> categories = new HashSet<GroupModel>();
_sqlConn.Open(); _sqlConn.Open();
SqliteCommand cmd = _sqlConn.CreateCommand(); SqliteCommand cmd = _sqlConn.CreateCommand();
cmd.CommandText = "SELECT * FROM category_data"; cmd.CommandText = "SELECT * FROM category_data";
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync(); await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
while (reader.Read()) while (reader.Read())
categories.Add(CategoryModel.Create(reader["name"].ToString(), reader["hex_color"].ToString(), reader["category_id"].ToString())); {
//categories.Add(GroupModel.Create(reader["name"].ToString(), reader["hex_color"].ToString(), reader["category_id"].ToString()));
}
_sqlConn.Close(); _sqlConn.Close();
return categories; return categories;
} }
@ -71,7 +81,9 @@ namespace SharpRss.Services
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync(); await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
while (reader.Read()) while (reader.Read())
feeds.Add(FeedModel.Create(reader["url"].ToString(), reader["feed_id"].ToString(), reader["category_id"].ToString())); {
//feeds.Add(FeedModel.Create(reader["url"].ToString(), reader["feed_id"].ToString(), reader["category_id"].ToString()));
}
_sqlConn.Close(); _sqlConn.Close();
return feeds; return feeds;
} }
@ -81,14 +93,18 @@ namespace SharpRss.Services
Log.Verbose("Checking database..."); Log.Verbose("Checking database...");
HashSet<string> failed = new HashSet<string>(); HashSet<string> failed = new HashSet<string>();
_sqlConn.Open(); _sqlConn.Open();
// Check category_data table Log.Verbose("Checking table: {Table}", _groupTable);
var queryResponse = await _sqlConn.QueryAsync("CREATE TABLE IF NOT EXISTS category_data (name STRING NOT NULL, hex_color STRING NOT NULL, path_icon STRING, category_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, CONSTRAINT name UNIQUE (name))");
if (queryResponse.Any()) failed.Add("category_data"); if (queryResponse.Any()) failed.Add("category_data");
// Check feed_data table Log.Verbose("Checking table: {Table}", _feedTable);
queryResponse = await _sqlConn.QueryAsync("CREATE TABLE IF NOT EXISTS feed_data (url STRING NOT NULL, feed_id STRING PRIMARY KEY, category_id STRING NOT NULL DEFAULT '', CONSTRAINT url, UNIQUE (url))"); 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))");
if (queryResponse.Any()) failed.Add("feed_data"); if (queryResponse.Any()) failed.Add("feed_data");
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)");
if (queryResponse.Any()) failed.Add("feed_item_data");
_sqlConn.Close(); _sqlConn.Close();
if (failed.Any()) if (failed.Any())
{ {

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -18,7 +19,7 @@ namespace SharpRss.Services
} }
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>() await _dbService.AddCategoriesAsync(new HashSet<CategoryModel>()
{ {
@ -34,56 +35,58 @@ namespace SharpRss.Services
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) public async Task<Feed> GetFeedAsync(string rssUrl)
{ {
return await FeedCache.GetFeed(rssUrl); /*return await FeedCache.GetFeed(rssUrl);*/
return new Feed();
} }
public async Task<HashSet<object>> GetAllUnsortedAsync() public async Task<HashSet<object>> GetAllUnsortedAsync()
{ {
HashSet<object> items = new HashSet<object>(); HashSet<object> items = new HashSet<object>();
var categories = await _dbService.GetCategoriesAsync(); /*var categories = await _dbService.GetCategoriesAsync();
var feeds = await _dbService.GetFeedsAsync(string.Empty); var feeds = await _dbService.GetFeedsAsync(string.Empty);
items.UnionWith(categories); items.UnionWith(categories);
items.UnionWith(feeds); items.UnionWith(feeds);*/
return items; return items;
} }
public async Task<HashSet<CategoryModel>> GetCategoriesAsync() public async Task<HashSet<GroupModel>> GetCategoriesAsync()
{ {
var result = await _dbService.GetCategoriesAsync(); /*var result = await _dbService.GetCategoriesAsync();
return result.OrderBy(x => x.Name).ToHashSet(); return result.OrderBy(x => x.Name).ToHashSet();*/
return new HashSet<GroupModel>();
} }
public async Task<HashSet<FeedModel>> GetFeedsAsync(CategoryModel? categoryModel = null) public async Task<HashSet<FeedModel>> GetFeedsAsync(GroupModel? categoryModel = null)
{ {
HashSet<FeedModel> feeds; HashSet<FeedModel> feeds = new HashSet<FeedModel>();
if (categoryModel != null) /*if (categoryModel != null)
feeds = await _dbService.GetFeedsAsync(categoryModel.CategoryId); feeds = await _dbService.GetFeedsAsync(categoryModel.Id);
else else
feeds = await _dbService.GetFeedsAsync(); feeds = await _dbService.GetFeedsAsync();*/
return feeds; return feeds;
} }
public async void AddCategoryAsync(string name, string? icon, string hexColor) public async void AddCategoryAsync(string name, string? icon, string hexColor)
{ {
CategoryModel categoryModel = new CategoryModel() /*GroupModel groupModel = new GroupModel()
{ {
Name = name Name = name
}; };
if (icon != null) if (icon != null)
categoryModel.PathIcon = icon; groupModel.PathIcon = icon;
if (!hexColor.IsNullEmptyWhiteSpace()) if (!hexColor.IsNullEmptyWhiteSpace())
categoryModel.HexColor = hexColor; groupModel.HexColor = hexColor;*/
await _dbService.AddCategoriesAsync(new HashSet<CategoryModel>() { categoryModel }); //await _dbService.AddCategoriesAsync(new HashSet<GroupModel>() { groupModel });
} }
public async void AddFeedAsync(string rssUrl, CategoryModel? category = null) public async void AddFeedAsync(string rssUrl, GroupModel? category = null)
{ {
FeedModel feedModel = new FeedModel(rssUrl, category); //FeedModel feedModel = new FeedModel(rssUrl, category);
await _dbService.AddFeedsAsync(new HashSet<FeedModel>() { feedModel }); //await _dbService.AddFeedsAsync(new HashSet<FeedModel>() { feedModel });
} }
public void Dispose() public void Dispose()

@ -1 +1 @@
Subproject commit af3abae0445b30c3ef58579a18e6e179eaea5986 Subproject commit b2a5173c7ffc21e83eb02c96b6e70434d7396d58

View File

@ -3,8 +3,10 @@ using System.IO;
using Serilog; using Serilog;
using Serilog.Formatting.Json; using Serilog.Formatting.Json;
using Serilog.Sinks.SystemConsole.Themes; using Serilog.Sinks.SystemConsole.Themes;
using SharpRss.Models;
using ToolQit; using ToolQit;
using ToolQit.Containers; using ToolQit.Containers;
using WebSharpRSS.Models;
namespace WebSharpRSS namespace WebSharpRSS
{ {

View File

@ -1,19 +1,11 @@
using CodeHollow.FeedReader; using SharpRss.Models;
using SharpRss.Models; using ToolQit;
namespace WebSharpRSS.Models namespace WebSharpRSS.Models
{ {
public class FeedItemData public class FeedItemData : FeedItemModel
{ {
public FeedItemData(FeedItem feedItem) public static FeedItemData? FromModel(FeedItemModel model) => Utilities.ConvertFrom<FeedItemData, FeedItemModel>(model);
{ public string HexColor { get; set; }
FeedItem = feedItem;
}
public FeedModel FeedModel { get; set; }
public FeedItem FeedItem { get; set; }
public string? Icon {get; set; }
public string? FaviconUrl { get; set; }
public string? CategoryColorHex { get; set; }
public bool Read { get; set; }
} }
} }

View File

@ -12,7 +12,7 @@ namespace WebSharpRSS.Models
{ {
public class TreeItemData public class TreeItemData
{ {
public TreeItemData(CategoryModel catModel, RssService rssService) public TreeItemData(GroupModel catModel, RssService rssService)
{ {
_service = rssService; _service = rssService;
CategoryModel = catModel; CategoryModel = catModel;
@ -28,7 +28,7 @@ namespace WebSharpRSS.Models
} }
private readonly RssService _service; private readonly RssService _service;
public readonly CategoryModel? CategoryModel; public readonly GroupModel? CategoryModel;
public readonly FeedModel? FeedModel; public readonly FeedModel? FeedModel;
private HashSet<FeedModel> _feedModels; private HashSet<FeedModel> _feedModels;
@ -69,16 +69,16 @@ namespace WebSharpRSS.Models
{ {
Title = CategoryModel.Name; Title = CategoryModel.Name;
Icon = Icons.Material.Filled.Category; Icon = Icons.Material.Filled.Category;
_feedModels = await _service.GetFeedsAsync(CategoryModel); /*_feedModels = await _service.GetFeedsAsync(CategoryModel);
if (_feedModels.Any()) if (_feedModels.Any())
Feeds = _feedModels.Select(x => new TreeItemData(x, _service)).OrderBy(x => x.Title).ToHashSet(); Feeds = _feedModels.Select(x => new TreeItemData(x, _service)).OrderBy(x => x.Title).ToHashSet();*/
} }
if (FeedModel != null) if (FeedModel != null)
{ {
try try
{ {
Feed = await _service.GetFeedAsync(FeedModel.FeedUrl); //Feed = await _service.GetFeedAsync(FeedModel.FeedUrl);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -7,7 +7,7 @@
@inject FeedStateContainer _stateContainer; @inject FeedStateContainer _stateContainer;
<MudStack Spacing="2" Class="ml-2 mr-2"> <MudStack Spacing="2" Class="ml-2 mr-2">
@foreach (var feedItemData in _itemDatas) @*@foreach (var feedItemData in _itemDatas)
{ {
<MudItem> <MudItem>
<MudCard> <MudCard>
@ -28,7 +28,7 @@
</MudCardContent> </MudCardContent>
</MudCard> </MudCard>
</MudItem> </MudItem>
} }*@
</MudStack> </MudStack>
@code { @code {
@ -42,11 +42,12 @@
UpdateFeeds(); UpdateFeeds();
InvokeAsync(StateHasChanged); InvokeAsync(StateHasChanged);
} }
private HashSet<FeedItemData> _itemDatas = new HashSet<FeedItemData>(); //private HashSet<FeedItemData> _itemDatas = new HashSet<FeedItemData>();
private TreeItemData? _treeItemData; //private TreeItemData? _treeItemData;
private void UpdateFeeds() private void UpdateFeeds()
{ {
if (_stateContainer.TreeItem == null) return;
/*if (_stateContainer.TreeItem == null) return;
_treeItemData = _stateContainer.TreeItem; _treeItemData = _stateContainer.TreeItem;
if (_treeItemData.Feed != null) if (_treeItemData.Feed != null)
{ {
@ -62,6 +63,6 @@
items.UnionWith(treeItem.Feed.Items.Select(x => new FeedItemData(x) { Icon = treeItem.Icon, FaviconUrl = treeItem.FaviconUrl, CategoryColorHex = _treeItemData.CategoryModel?.HexColor })); items.UnionWith(treeItem.Feed.Items.Select(x => new FeedItemData(x) { Icon = treeItem.Icon, FaviconUrl = treeItem.FaviconUrl, CategoryColorHex = _treeItemData.CategoryModel?.HexColor }));
_itemDatas = items.OrderBy(x => x.FeedItem.PublishingDate).Reverse().ToHashSet(); _itemDatas = items.OrderBy(x => x.FeedItem.PublishingDate).Reverse().ToHashSet();
} }
} }*/
} }
} }

View File

@ -6,13 +6,12 @@
@using WebSharpRSS.Models; @using WebSharpRSS.Models;
@using ToolQit.Extensions; @using ToolQit.Extensions;
@inject NavigationManager _navManager;
@inject FeedStateContainer _stateContainer; @inject FeedStateContainer _stateContainer;
@inject RssService _rssService @inject RssService _rssService
<MudStack Spacing="2"> <MudStack Spacing="2">
<MudTreeView Items="_guideItems" @bind-SelectedValue="SelectedItem" Hover="true"> <MudTreeView Items="_guideItems" @bind-SelectedValue="SelectedItem" Hover="true">
<ItemTemplate> @*<ItemTemplate>
<MudTreeViewItem @bind-Expanded="@context.IsExpanded" Items="@context.Feeds" Value="@context" CanExpand="@context.HasChild" @onclick="ItemClicked"> <MudTreeViewItem @bind-Expanded="@context.IsExpanded" Items="@context.Feeds" Value="@context" CanExpand="@context.HasChild" @onclick="ItemClicked">
<Content> <Content>
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%"> <div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
@ -34,7 +33,7 @@
</div> </div>
</Content> </Content>
</MudTreeViewItem> </MudTreeViewItem>
</ItemTemplate> </ItemTemplate>*@
</MudTreeView> </MudTreeView>
</MudStack> </MudStack>
@ -59,8 +58,8 @@
protected override async void OnInitialized() protected override async void OnInitialized()
{ {
Log.Verbose("Loading guide data..."); Log.Verbose("Loading guide data...");
HashSet<object> items = await _rssService.GetAllUnsortedAsync(); /*HashSet<object> items = await _rssService.GetAllUnsortedAsync();
_guideItems.UnionWith(items.Select(x => x is CategoryModel model ? new TreeItemData(model, _rssService) : x is FeedModel feedModel ? new TreeItemData(feedModel, _rssService) : throw new ArgumentException("Arg x is invalid!"))); _guideItems.UnionWith(items.Select(x => x is CategoryModel model ? new TreeItemData(model, _rssService) : x is FeedModel feedModel ? new TreeItemData(feedModel, _rssService) : throw new ArgumentException("Arg x is invalid!")));*/
StateHasChanged(); StateHasChanged();
Log.Verbose("Guide initialized!"); Log.Verbose("Guide initialized!");

View File

@ -5,6 +5,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>10</LangVersion> <LangVersion>10</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>