mirror of
https://github.com/hmaxnl/SharpRSS.git
synced 2024-11-09 23:44:20 +01:00
417 lines
22 KiB
C#
417 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Dapper;
|
|
using Microsoft.Data.Sqlite;
|
|
using Serilog;
|
|
using SharpRss.Models;
|
|
|
|
namespace SharpRss
|
|
{
|
|
public static class DbAccess_Old
|
|
{
|
|
//TODO: Rename group => category.
|
|
//TODO: Reworking feed => model/db implementation.
|
|
private static bool _isInitialized;
|
|
private static readonly string ConnectionString = $"Data Source={Path.Combine(Environment.CurrentDirectory, "sharp_rss.sqlite")};";
|
|
private const string GroupTable = "group_data";
|
|
private const string FeedTable = "feed_data";
|
|
private const string FeedItemTable = "feed_item_data";
|
|
|
|
// Groups
|
|
public static async Task<HashSet<CategoryModel>> GetCategoriesAsync(string? categoryId = null)
|
|
{
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using SqliteCommand cmd = new SqliteCommand(categoryId != null ? $"SELECT * FROM {GroupTable} WHERE id=@gId;" : $"SELECT * FROM {GroupTable}", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("gId", categoryId)
|
|
}
|
|
};
|
|
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
|
|
HashSet<CategoryModel> categories = new HashSet<CategoryModel>();
|
|
await using SqliteCommand cmdFeedCount = new SqliteCommand($"SELECT COUNT(*) FROM {FeedTable} WHERE group_id=@groupId", dbc);
|
|
while (reader.Read())
|
|
{
|
|
cmdFeedCount.Parameters.Clear();
|
|
cmdFeedCount.Parameters.Add(new SqliteParameter("groupId", reader["id"].ToString()));
|
|
using SqliteDataReader countReader = await cmdFeedCount.ExecuteReaderAsync();
|
|
int count = countReader.Read() ? countReader.GetInt32(0) : 0;
|
|
|
|
categories.Add(new CategoryModel()
|
|
{
|
|
Name = reader["name"].ToString(),
|
|
FeedCount = count,
|
|
HexColor = reader["hex_color"].ToString(),
|
|
Icon = reader["icon"].ToString(),
|
|
Id = reader["id"].ToString()
|
|
});
|
|
}
|
|
return categories;
|
|
}
|
|
public static async Task<bool> SetCategoryAsync(CategoryModel categoryModel)
|
|
{
|
|
bool result = false;
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using 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)", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("id", categoryModel.Id),
|
|
new SqliteParameter("hexColor", categoryModel.HexColor),
|
|
new SqliteParameter("icon", categoryModel.Icon),
|
|
new SqliteParameter("name", categoryModel.Name)
|
|
}
|
|
};
|
|
int affected = await cmd.ExecuteNonQueryAsync();
|
|
if (affected != 0)
|
|
result = true;
|
|
return result;
|
|
}
|
|
public static async Task<bool> RemoveCategoryAsync(CategoryModel categoryModel)
|
|
{
|
|
bool result = false;
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
// Remove the group and remove the feeds that were part of the group.
|
|
await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {GroupTable} WHERE id=@id; UPDATE {FeedTable} SET group_id=NULL WHERE group_id=@id", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("id", categoryModel.Id)
|
|
}
|
|
};
|
|
int affected = await cmd.ExecuteNonQueryAsync();
|
|
if (affected != 0)
|
|
result = true;
|
|
return result;
|
|
}
|
|
// Feeds
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="groupId">Empty = ungrouped feeds | null = all feeds | id = grouped feeds</param>
|
|
/// <returns></returns>
|
|
public static async Task<HashSet<FeedModel>> GetFeedsAsync(string? groupId = null)
|
|
{
|
|
HashSet<FeedModel> feeds = new HashSet<FeedModel>();
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using SqliteCommand cmd = new SqliteCommand(groupId != null ? $"SELECT * FROM {FeedTable} WHERE group_id=@groupId" : $"SELECT * FROM {FeedTable}", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("groupId", groupId ?? string.Empty)
|
|
}
|
|
};
|
|
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
|
|
while (!reader.IsClosed && reader.Read())
|
|
feeds.Add(await ReaderToFeedModel(reader));
|
|
return feeds;
|
|
}
|
|
public static async Task<FeedModel?> GetFeedAsync(string url)
|
|
{
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
FeedModel? feed = null;
|
|
//TODO: Use dapper to simplify this query.
|
|
await using SqliteCommand cmd = new SqliteCommand($"SELECT * FROM {FeedTable} WHERE url=@Url", dbc)
|
|
{
|
|
Parameters = { new SqliteParameter("Url", url) }
|
|
};
|
|
try
|
|
{
|
|
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
|
|
if (reader.Read())
|
|
feed = await ReaderToFeedModel(reader);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Error while fetching feed from db.");
|
|
}
|
|
return feed;
|
|
}
|
|
public static async Task<FeedModel?> SetFeedAsync(FeedModel feedModel)
|
|
{
|
|
FeedModel? feed = null;
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedTable} (url, title, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url, original_document) VALUES (@url, @title, @groupId, @feedType, @description, @language, @copyright, @dateAdded, @lastUpdated, @imageUrl, @originalDoc); SELECT * FROM {FeedTable} WHERE url=@url", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("url", feedModel.OriginalUrl ?? string.Empty),
|
|
new SqliteParameter("title", feedModel.Title ?? string.Empty),
|
|
new SqliteParameter("groupId", feedModel.CategoryId ?? string.Empty),
|
|
new SqliteParameter("feedType", feedModel.FeedType ?? string.Empty),
|
|
new SqliteParameter("description", feedModel.Description ?? string.Empty),
|
|
new SqliteParameter("language", feedModel.Language ?? string.Empty),
|
|
new SqliteParameter("copyright", feedModel.Copyright ?? string.Empty),
|
|
new SqliteParameter("dateAdded", feedModel.PublicationDate?.ToUnixTimeMilliseconds() ?? 0),
|
|
new SqliteParameter("lastUpdated", feedModel.LastUpdated?.ToUnixTimeMilliseconds() ?? 0),
|
|
new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty)
|
|
}
|
|
};
|
|
try
|
|
{
|
|
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
|
|
feed = await ReaderToFeedModel(reader);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Database error, adding feed model to database failed!");
|
|
return feed;
|
|
}
|
|
return feed;
|
|
/*await using SqliteTransaction transaction = dbc.BeginTransaction();
|
|
try
|
|
{
|
|
foreach (var feedModel in feedModels)
|
|
{
|
|
//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", dbc)
|
|
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)", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("id", feedModel.Id ?? string.Empty),
|
|
new SqliteParameter("url", feedModel.Url ?? string.Empty),
|
|
new SqliteParameter("title", feedModel.Title ?? string.Empty),
|
|
new SqliteParameter("groupId", feedModel.GroupId ?? string.Empty),
|
|
new SqliteParameter("feedType", feedModel.FeedType ?? string.Empty),
|
|
new SqliteParameter("description", feedModel.Description ?? string.Empty),
|
|
new SqliteParameter("language", feedModel.Language ?? string.Empty),
|
|
new SqliteParameter("copyright", feedModel.Copyright ?? string.Empty),
|
|
new SqliteParameter("dateAdded", feedModel.DateAdded?.ToUnixTimeMilliseconds()),
|
|
new SqliteParameter("lastUpdated", feedModel.LastUpdated?.ToUnixTimeMilliseconds()),
|
|
new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty),
|
|
new SqliteParameter("originalDoc", feedModel.OriginalDocument ?? string.Empty)
|
|
},
|
|
Transaction = transaction
|
|
};
|
|
await cmd.ExecuteNonQueryAsync();
|
|
}
|
|
await transaction.CommitAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await transaction.RollbackAsync();
|
|
Log.Error(ex, "Error on inserting feeds to db.");
|
|
return false;
|
|
}*/
|
|
}
|
|
|
|
public static async Task FetchFeedItemsAsync(string[]? feedUrls = null)
|
|
{
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
HashSet<FeedModel> dbFeeds = new HashSet<FeedModel>();
|
|
string query = $"SELECT * FROM {FeedTable}";
|
|
if (feedUrls != null)
|
|
{
|
|
List<string>? feedUrlsFormatted = feedUrls.Select(s => $"'{s}'").ToList();
|
|
query = $"SELECT * FROM {FeedTable} WHERE url IN(({string.Join(", ", feedUrlsFormatted)}))";
|
|
}
|
|
await using SqliteCommand fetchCmd = new SqliteCommand(query, dbc);
|
|
await using SqliteDataReader reader = await fetchCmd.ExecuteReaderAsync();
|
|
while (reader.Read())
|
|
{
|
|
dbFeeds.Add(await ReaderToFeedModel(reader));
|
|
}
|
|
HashSet<FeedItemModel> feedItems = new HashSet<FeedItemModel>();
|
|
foreach (var dbFeed in dbFeeds)
|
|
{
|
|
/*GenericSyndicationFeed syndication = new GenericSyndicationFeed();
|
|
syndication.Load(dbFeed.OriginalDocument);*/
|
|
//TODO: Get items and add to db
|
|
}
|
|
}
|
|
|
|
public static async Task<bool> RemoveFeedAsync(FeedModel feedModel)
|
|
{
|
|
bool result = false;
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {FeedTable} WHERE url=@Url; UPDATE {FeedItemTable} SET feed_id=NULL WHERE feed_id=@Url", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("Url", feedModel.OriginalUrl)
|
|
}
|
|
};
|
|
int affected = await cmd.ExecuteNonQueryAsync();
|
|
if (affected != 0)
|
|
result = true;
|
|
return result;
|
|
}
|
|
// Feed items
|
|
public static async Task<HashSet<FeedItemModel>> GetFeedItemsAsync(string[]? feedIds = null)
|
|
{
|
|
List<string>? formattedIds = feedIds?.Select(s => $"'{s}'").ToList();
|
|
HashSet<FeedItemModel> feedItems = new HashSet<FeedItemModel>();
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using SqliteCommand cmd = new SqliteCommand(
|
|
formattedIds != null
|
|
? $"SELECT * FROM {FeedItemTable} WHERE feed_id IN ({string.Join(", ", formattedIds)})"
|
|
: $"SELECT * FROM {FeedItemTable}", dbc);
|
|
|
|
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
|
|
while (reader.Read())
|
|
{
|
|
FeedItemModel feedItemModel = new FeedItemModel()
|
|
{
|
|
Id = reader["id"].ToString(),
|
|
FeedUrl = reader["feed_url"].ToString(),
|
|
Read = int.TryParse(reader["read"].ToString(), out int parsedValue) && parsedValue != 0,
|
|
Title = reader["title"].ToString(),
|
|
Description = reader["description"].ToString(),
|
|
Link = reader["link"].ToString(),
|
|
LastUpdated =
|
|
DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(reader["last_updated"].ToString())),
|
|
PublishingDate =
|
|
DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(reader["publishing_date"].ToString())),
|
|
Authors = reader["authors"].ToString().ToString().Split(','),
|
|
Categories = reader["categories"].ToString().Split(','),
|
|
Content = reader["content"].ToString()
|
|
};
|
|
feedItems.Add(feedItemModel);
|
|
}
|
|
return feedItems;
|
|
}
|
|
|
|
public static async Task<int> SetFeedItemsAsync(HashSet<FeedItemModel> items)
|
|
{
|
|
int result = 0;
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using SqliteTransaction transaction = dbc.BeginTransaction();
|
|
await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedItemTable} (id, feed_url, read, title, description, link, last_updated, publishing_date, authors, categories, content)" +
|
|
$"VALUES (IFNULL((SELECT id FROM {FeedItemTable} WHERE link=@link), @id), @feedUrl, @read, @title, @description, @link, @lastUpdated, @publishingDate, @authors, @categories, @content)", dbc)
|
|
{
|
|
Transaction = transaction
|
|
};
|
|
foreach (FeedItemModel item in items)
|
|
{
|
|
cmd.Parameters.Clear();
|
|
cmd.Parameters.Add(new SqliteParameter("id", item.Id ?? string.Empty));
|
|
cmd.Parameters.Add(new SqliteParameter("feedUrl", item.FeedUrl ?? string.Empty));
|
|
cmd.Parameters.Add(new SqliteParameter("read", item.Read ? 1 : 0));
|
|
cmd.Parameters.Add(new SqliteParameter("type", item.Type ?? string.Empty));
|
|
cmd.Parameters.Add(new SqliteParameter("title", item.Title ?? string.Empty));
|
|
cmd.Parameters.Add(new SqliteParameter("description", item.Description ?? string.Empty));
|
|
cmd.Parameters.Add(new SqliteParameter("link", item.Link ?? string.Empty));
|
|
cmd.Parameters.Add(new SqliteParameter("lastUpdated", item.LastUpdated?.ToUnixTimeMilliseconds()));
|
|
cmd.Parameters.Add(new SqliteParameter("publishingDate", item.PublishingDate?.ToUnixTimeMilliseconds() ?? 0));
|
|
cmd.Parameters.Add(new SqliteParameter("authors", item.Authors != null ? string.Join(',', item.Authors) : 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 (dbc.State != ConnectionState.Open)
|
|
dbc.Open();
|
|
int affected = await cmd.ExecuteNonQueryAsync();
|
|
if (affected == 0)
|
|
Log.Verbose("Could not set feed item: {FeedLink}", item.Link);
|
|
else
|
|
result += affected;
|
|
}
|
|
transaction.Commit();
|
|
return result;
|
|
}
|
|
public static async Task<bool> RemoveFeedItemAsync(FeedItemModel itemModel)
|
|
{
|
|
bool result = false;
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using SqliteCommand cmd = new SqliteCommand($"DELETE FROM {FeedItemTable} WHERE id=@id", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("id", itemModel.Id)
|
|
}
|
|
};
|
|
int affected = await cmd.ExecuteNonQueryAsync();
|
|
if (affected != 0)
|
|
result = true;
|
|
return result;
|
|
}
|
|
public static async Task<CategoryModel?> GetGroupFromFeedItemAsync(FeedItemModel feedItem)
|
|
{
|
|
CategoryModel? result = null;
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using SqliteCommand cmd = new SqliteCommand($"SELECT * FROM {GroupTable} WHERE id=(SELECT group_id FROM {FeedTable} WHERE id=@fId)", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter ("fId", feedItem.Id)
|
|
}
|
|
};
|
|
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
|
|
HashSet<CategoryModel>? groups = null;
|
|
/*if (reader.Read())
|
|
groups = await GetCategoriesAsync(reader["group_id"].ToString());*/
|
|
if (groups != null && groups.Any())
|
|
result = groups.FirstOrDefault();
|
|
return result;
|
|
}
|
|
private static async Task<FeedModel> ReaderToFeedModel(SqliteDataReader reader)
|
|
{
|
|
FeedModel fetchedFeed = new FeedModel()
|
|
{
|
|
OriginalUrl = reader["url"].ToString(),
|
|
Title = reader["title"].ToString(),
|
|
CategoryId = reader["group_id"].ToString(),
|
|
FeedType = reader["feed_type"].ToString(),
|
|
Description = reader["description"].ToString(),
|
|
Language = reader["language"].ToString(),
|
|
Copyright = reader["copyright"].ToString(),
|
|
PublicationDate = 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()
|
|
};
|
|
//TODO: Set group on insert
|
|
/*var groupFetch = await GetGroupsAsync(fetchedFeed.GroupId);
|
|
if (groupFetch.Any())
|
|
fetchedFeed.Group = groupFetch.First();
|
|
else
|
|
Log.Warning("Could not get group from feed: {FeedId}", fetchedFeed.Id);*/
|
|
return fetchedFeed;
|
|
}
|
|
|
|
//===
|
|
public static async void Initialize()
|
|
{
|
|
if (_isInitialized) return;
|
|
Log.Verbose("Checking database...");
|
|
HashSet<string> failed = new HashSet<string>();
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
Log.Verbose("Checking table: {Table}", "category");
|
|
var queryResponse = await dbc.QueryAsync("CREATE TABLE IF NOT EXISTS category (name STRING NOT NULL, hex_color STRING NOT NULL, icon STRING, id STRING PRIMARY KEY)");
|
|
if (queryResponse.Any()) failed.Add("category");
|
|
|
|
Log.Verbose("Checking table: {Table}", "feed");
|
|
queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed (url STRING PRIMARY KEY, title STRING, group_id STRING, feed_type STRING, description STRING, language STRING, copyright STRING, date_added INT, last_updated INT, image_url STRING, original_document STRING)");
|
|
if (queryResponse.Any()) failed.Add("feed");
|
|
|
|
Log.Verbose("Checking table: {Table}", "feed_item");
|
|
queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed_item (id STRING PRIMARY KEY, feed_url STRING, read INT, title STRING, description STRING, link STRING, last_updated INT, publishing_date INT, authors STRING, categories STRING, content STRING)");
|
|
if (queryResponse.Any()) failed.Add("feed_item");
|
|
|
|
if (failed.Any())
|
|
{
|
|
var joined = string.Join(',', failed);
|
|
Log.Error("Failed to initialize table(s): {TableNames}", joined);
|
|
}
|
|
else
|
|
Log.Verbose("Checking database done!");
|
|
_isInitialized = true;
|
|
}
|
|
}
|
|
} |