diff --git a/SharpRss/Models/CategoryModel.cs b/SharpRss/Models/CategoryModel.cs index 5acbf6b..8766b49 100644 --- a/SharpRss/Models/CategoryModel.cs +++ b/SharpRss/Models/CategoryModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using ToolQit.Extensions; namespace SharpRss.Models { @@ -7,18 +8,26 @@ namespace SharpRss.Models /// 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 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 Feeds { get; set; } + public string HexColor { get; set; } + public string CategoryId { get; private set; } } } diff --git a/SharpRss/Models/FeedModel.cs b/SharpRss/Models/FeedModel.cs index d4ba1a9..887966a 100644 --- a/SharpRss/Models/FeedModel.cs +++ b/SharpRss/Models/FeedModel.cs @@ -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; + }*/ } } diff --git a/SharpRss/RssService.cs b/SharpRss/RssService.cs deleted file mode 100644 index c24a071..0000000 --- a/SharpRss/RssService.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using CodeHollow.FeedReader; -using SharpRss.Models; - -namespace SharpRss -{ - /// - /// Managing RSS feeds and categories. - /// - public class RssService - { - public RssService() - { - /// Storage options: - /// - Database - /// - File - /// - Memory - combined.UnionWith(feedSet); - combined.UnionWith(feedSet2); - } - - private static HashSet feedSet = new HashSet() - { - new FeedModel("http://fedoramagazine.org/feed/"), - new FeedModel("https://www.nasa.gov/rss/dyn/breaking_news.rss"), - }; - private static HashSet feedSet2 = new HashSet() - { - new FeedModel("https://journals.plos.org/plosone/feed/atom"), - new FeedModel("https://itsfoss.com/feed") - }; - private static HashSet combined = new HashSet(); - - HashSet set = new HashSet() - { - new CategoryModel("RSS", feedSet), - new CategoryModel("Tech", feedSet2) - }; - - public async Task> GetCategories() - { - return set; - } - - public async Task> GetAllFeeds() - { - return combined; - } - - - /// Old - - public async Task 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> GetFeedsFromCatAsync(CategoryModel category) - { - return new HashSet(); - } - - private readonly string[] _feeds = { "https://www.reddit.com/r/freshrss/.rss", "http://fedoramagazine.org/" }; - } -} \ No newline at end of file diff --git a/SharpRss/Services/DatabaseService.cs b/SharpRss/Services/DatabaseService.cs new file mode 100644 index 0000000..7a032fe --- /dev/null +++ b/SharpRss/Services/DatabaseService.cs @@ -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 AddCategoriesAsync(HashSet 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 AddFeedsAsync(HashSet 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> GetCategoriesAsync() + { + HashSet categories = new HashSet(); + _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> GetFeedsAsync(string? categoryId = null) + { + HashSet feeds = new HashSet(); + _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(); + } + } +} \ No newline at end of file diff --git a/SharpRss/Services/RssService.cs b/SharpRss/Services/RssService.cs new file mode 100644 index 0000000..a2423a6 --- /dev/null +++ b/SharpRss/Services/RssService.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using SharpRss.Models; + +namespace SharpRss.Services +{ + /// + /// Managing RSS feeds and categories. + /// + public class RssService + { + public RssService() + { + _dbService = new DatabaseService(); + Initialize(); + } + private readonly DatabaseService _dbService; + + private async void Initialize() + { + //HashSet categoryModels = await _dbService.GetCategoriesAsync(); + } + + public async Task> GetAllAsync() + { + HashSet items = new HashSet(); + return items; + } + + public async Task> GetCategoriesAsync() + { + return new HashSet(); + } + + public async Task> GetFeedsAsync(CategoryModel? categoryModel = null) + { + HashSet feeds = new HashSet(); + 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 feedSet = new HashSet() + { + new FeedModel("http://fedoramagazine.org/feed/"), + new FeedModel("https://www.nasa.gov/rss/dyn/breaking_news.rss"), + }; + private static HashSet feedSet2 = new HashSet() + { + new FeedModel("https://journals.plos.org/plosone/feed/atom"), + new FeedModel("https://itsfoss.com/feed") + };*/ + + /*HashSet set = new HashSet() + { + new CategoryModel("RSS", feedSet), + new CategoryModel("Tech", feedSet2) + };*/ + } +} \ No newline at end of file diff --git a/SharpRss/SharpRss.csproj b/SharpRss/SharpRss.csproj index 6bef392..9edc2d0 100644 --- a/SharpRss/SharpRss.csproj +++ b/SharpRss/SharpRss.csproj @@ -9,6 +9,8 @@ + + diff --git a/WebSharpRSS/Models/FeedStateContainer.cs b/WebSharpRSS/Models/FeedStateContainer.cs index 4f2cce2..e67f191 100644 --- a/WebSharpRSS/Models/FeedStateContainer.cs +++ b/WebSharpRSS/Models/FeedStateContainer.cs @@ -1,4 +1,6 @@ -using SharpRss.Models; +using System; +using System.Collections.Generic; +using SharpRss.Models; namespace WebSharpRSS.Models { diff --git a/WebSharpRSS/Models/TreeItemData.cs b/WebSharpRSS/Models/TreeItemData.cs index d64fb57..6aed67e 100644 --- a/WebSharpRSS/Models/TreeItemData.cs +++ b/WebSharpRSS/Models/TreeItemData.cs @@ -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); diff --git a/WebSharpRSS/Pages/Index.razor b/WebSharpRSS/Pages/Index.razor index 4ad8a17..3cb14bb 100644 --- a/WebSharpRSS/Pages/Index.razor +++ b/WebSharpRSS/Pages/Index.razor @@ -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) { - + @feedItem.Title @feedItem.Description - @feedItem.PublishingDateString + @feedItem.PublishingDate.ToString() @@ -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(); } } } \ No newline at end of file diff --git a/WebSharpRSS/Program.cs b/WebSharpRSS/Program.cs index ec61f9f..cf5d286 100644 --- a/WebSharpRSS/Program.cs +++ b/WebSharpRSS/Program.cs @@ -6,6 +6,7 @@ using MudBlazor.Services; using Serilog; using SharpRss; using SharpRss.Models; +using SharpRss.Services; using ToolQit; using WebSharpRSS; using WebSharpRSS.Models; diff --git a/WebSharpRSS/Shared/SideGuide.razor b/WebSharpRSS/Shared/SideGuide.razor index 5a1dc86..d269e74 100644 --- a/WebSharpRSS/Shared/SideGuide.razor +++ b/WebSharpRSS/Shared/SideGuide.razor @@ -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 - + @@ -38,7 +39,7 @@ @code { - public HashSet Categories = new HashSet(); + public HashSet GuideItems = new HashSet(); private TreeItemData? _selecteditem; private TreeItemData? SelectedItem { @@ -58,14 +59,13 @@ { } - //_navManager.NavigateTo("/"); } protected override async void OnInitialized() { Log.Verbose("Loading guide data..."); - HashSet cats = await _rssService.GetCategories(); - await Task.Run(() => Categories.UnionWith(cats.Select(x => new TreeItemData(x)).ToHashSet())); + /*HashSet cats = await _rssService.GetAllAsync(); + await Task.Run(() => Categories.UnionWith(cats.Select(x => new TreeItemData(x)).ToHashSet()));*/ StateHasChanged(); Log.Verbose(" Guide initialized!"); diff --git a/WebSharpRSS/sharp_rss.db b/WebSharpRSS/sharp_rss.db new file mode 100644 index 0000000..dfe2158 Binary files /dev/null and b/WebSharpRSS/sharp_rss.db differ