mirror of
https://github.com/hmaxnl/SharpRSS.git
synced 2024-09-20 01:54:20 +02:00
288 lines
15 KiB
C#
288 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Common;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Dapper;
|
|
using Microsoft.Data.Sqlite;
|
|
using Serilog;
|
|
using SharpRss.Models;
|
|
|
|
namespace SharpRss
|
|
{
|
|
internal static class DbAccess
|
|
{
|
|
private static readonly string ConnectionString = $"Data Source={Path.Combine(Environment.CurrentDirectory, "sharp_rss.sqlite")};";
|
|
private static bool _isInitialized;
|
|
|
|
public static async Task SetSyndicationAsync(SyndicationContainer synContainer)
|
|
{
|
|
if (synContainer.Category != null)
|
|
{
|
|
CategoryModel? catModel = await SetCategoryAsync(synContainer.Category);
|
|
if (catModel != null)
|
|
synContainer.FeedModel.CategoryId = catModel.Id;
|
|
}
|
|
if (synContainer.FeedModel != null)
|
|
await SetFeedAsync(synContainer.FeedModel);
|
|
if (synContainer.FeedItems != null && synContainer.FeedItems.Any())
|
|
await SetFeedItemsAsync(synContainer.FeedItems);
|
|
}
|
|
|
|
public static async Task<HashSet<CategoryModel>> GetCategoriesAsync()
|
|
{
|
|
HashSet<CategoryModel> categories = new HashSet<CategoryModel>();
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
await using DbDataReader reader = await dbc.ExecuteReaderAsync("SELECT * FROM category");
|
|
while (await reader.ReadAsync())
|
|
{
|
|
CategoryModel categoryModel = new CategoryModel()
|
|
{
|
|
Id = reader["id"].ToString(),
|
|
Name = reader["name"].ToString(),
|
|
HexColor = reader["hex_color"].ToString(),
|
|
FeedCount = 0, // Not implemented.
|
|
Icon = reader["icon"].ToString()
|
|
};
|
|
categories.Add(categoryModel);
|
|
}
|
|
return categories;
|
|
}
|
|
public static async Task<CategoryModel?> SetCategoryAsync(CategoryModel category)
|
|
{
|
|
CategoryModel? modelReturn = null;
|
|
if (category == null) return modelReturn;
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
int affected = await dbc.ExecuteAsync("INSERT OR REPLACE INTO category (id, hex_color, icon, name) VALUES (IFNULL((SELECT id FROM category WHERE name=@Name), @Id), @HexColor, @Icon, @Name)",
|
|
new { category.Id, category.HexColor, category.Icon, category.Name });
|
|
if (affected <= 0) return modelReturn;
|
|
var catModel = await GetCategoriesAsync();
|
|
modelReturn = catModel.Where(x => x.Name == category.Name).ToHashSet().FirstOrDefault() ?? null;
|
|
return modelReturn;
|
|
}
|
|
public static async Task<bool> DeleteCategory(CategoryModel category)
|
|
{
|
|
if (category == null) return false;
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
int affected = await dbc.ExecuteAsync("DELETE FROM category WHERE id=@Id; UPDATE feed SET category_id=NULL WHERE category_id=@Id",new { category.Id });
|
|
return affected > 0;
|
|
}
|
|
|
|
public static async Task SetFeedAsync(FeedModel feed)
|
|
{
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
/*await using SqliteCommand cmd = new SqliteCommand(@"INSERT OR REPLACE INTO feed
|
|
(url,
|
|
title,
|
|
category_id,
|
|
feed_type,
|
|
feed_version,
|
|
description,
|
|
language,
|
|
copyright,
|
|
publication_date,
|
|
last_updated,
|
|
categories,
|
|
image_url)
|
|
VALUES (
|
|
@Url,
|
|
@Title,
|
|
@CategoryId,
|
|
@FeedType,
|
|
@FeedVersion,
|
|
@Description,
|
|
@Language,
|
|
@Copyright,
|
|
@PublicationDate,
|
|
@LastUpdated,
|
|
@Categories,
|
|
@ImageUrl)", dbc)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("Url", feed.OriginalUrl ?? string.Empty),
|
|
new SqliteParameter("Title", feed.Title ?? string.Empty),
|
|
new SqliteParameter("CategoryId", feed.CategoryId ?? string.Empty),
|
|
new SqliteParameter("FeedType", feed.FeedType ?? string.Empty),
|
|
new SqliteParameter("FeedVersion", feed.FeedVersion ?? string.Empty),
|
|
new SqliteParameter("Description", feed.Description ?? string.Empty),
|
|
new SqliteParameter("Language", feed.Language ?? string.Empty),
|
|
new SqliteParameter("Copyright", feed.Copyright ?? string.Empty),
|
|
new SqliteParameter("PublicationDate", feed.PublicationDate?.ToUnixTimeMilliseconds() ?? 0),
|
|
new SqliteParameter("LastUpdated", feed.LastUpdated?.ToUnixTimeMilliseconds() ?? 0),
|
|
new SqliteParameter("Categories", feed.Categories != null && feed.Categories.Any() ? string.Join(',', feed.Categories) : string.Empty),
|
|
new SqliteParameter("ImageUrl", feed.ImageUrl ?? string.Empty)
|
|
}
|
|
};
|
|
int exec = await cmd.ExecuteNonQueryAsync();*/
|
|
int affected = await dbc.ExecuteAsync(@"INSERT OR REPLACE INTO feed
|
|
(url,
|
|
title,
|
|
category_id,
|
|
feed_type,
|
|
feed_version,
|
|
description,
|
|
language,
|
|
copyright,
|
|
publication_date,
|
|
last_updated,
|
|
categories,
|
|
image_url)
|
|
VALUES (
|
|
@Url,
|
|
@Title,
|
|
@CategoryId,
|
|
@FeedType,
|
|
@FeedVersion,
|
|
@Description,
|
|
@Language,
|
|
@Copyright,
|
|
@PublicationDate,
|
|
@LastUpdated,
|
|
@Categories,
|
|
@ImageUrl)",
|
|
new
|
|
{
|
|
Url = feed.OriginalUrl ?? string.Empty,
|
|
Title = feed.Title ?? string.Empty,
|
|
CategoryId = feed.CategoryId ?? string.Empty,
|
|
FeedType = feed.FeedType ?? string.Empty,
|
|
FeedVersion = feed.FeedVersion ?? string.Empty,
|
|
Description = feed.Description ?? string.Empty,
|
|
Language = feed.Language ?? string.Empty,
|
|
Copyright = feed.Copyright ?? string.Empty,
|
|
PublicationDate = feed.PublicationDate?.ToUnixTimeMilliseconds() ?? 0,
|
|
LastUpdated = feed.LastUpdated?.ToUnixTimeMilliseconds() ?? 0,
|
|
Categories = feed.Categories != null && feed.Categories.Any() ? string.Join(',', feed.Categories) : string.Empty,
|
|
ImageUrl = feed.ImageUrl ?? string.Empty
|
|
});
|
|
if (affected == 0)
|
|
Log.Warning("Failed to add feed: {FeedUrl}", feed.OriginalUrl);
|
|
}
|
|
public static async Task<HashSet<FeedModel>> GetFeedsAsync(string[]? categoryIds = null)
|
|
{
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
HashSet<FeedModel> feeds = new HashSet<FeedModel>();
|
|
await using DbDataReader reader = await dbc.ExecuteReaderAsync(categoryIds == null ? "SELECT * FROM feed WHERE category_id == ''" : "SELECT * FROM feed WHERE category_id IN(@CatIds)", new { CatIds = categoryIds });
|
|
while (await reader.ReadAsync())
|
|
{
|
|
FeedModel feedModel = new FeedModel()
|
|
{
|
|
OriginalUrl = reader["url"].ToString(),
|
|
Title = reader["title"].ToString(),
|
|
CategoryId = reader["category_id"].ToString(),
|
|
FeedType = reader["feed_type"].ToString(),
|
|
FeedVersion = reader["feed_version"].ToString(),
|
|
Description = reader["description"].ToString(),
|
|
Language = reader["language"].ToString(),
|
|
Copyright = reader["copyright"].ToString(),
|
|
PublicationDate = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(reader["publication_date"].ToString())),
|
|
LastUpdated = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(reader["last_updated"].ToString())),
|
|
Categories = reader["categories"].ToString().Split(','),
|
|
ImageUrl = reader["image_url"].ToString()
|
|
};
|
|
feeds.Add(feedModel);
|
|
}
|
|
return feeds;
|
|
}
|
|
|
|
public static async Task SetFeedItemsAsync(HashSet<FeedItemModel> items)
|
|
{
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
int totalAffected = 0;
|
|
await using SqliteTransaction dbTransaction = dbc.BeginTransaction();
|
|
foreach (FeedItemModel item in items)
|
|
{
|
|
/*await using SqliteCommand cmd = new SqliteCommand(@"INSERT OR REPLACE INTO feed_item (id, feed_url, read, title, description, link, last_updated, publishing_date, authors, categories, content)
|
|
VALUES (@Id, @FeedUrl, @Read, @Title, @Description, @Link, @LastUpdated, @PublishingDate, @Authors, @Categories, @Content)", dbc, dbTransaction)
|
|
{
|
|
Parameters =
|
|
{
|
|
new SqliteParameter("Id", item.Id ?? string.Empty),
|
|
new SqliteParameter("FeedUrl", item.FeedUrl ?? string.Empty),
|
|
new SqliteParameter("Read", item.Read.ToString()),
|
|
new SqliteParameter("Title", item.Title),
|
|
new SqliteParameter("Description", item.Description ?? string.Empty),
|
|
new SqliteParameter("Link", item.Link ?? string.Empty),
|
|
new SqliteParameter("LastUpdated", item.LastUpdated?.ToUnixTimeMilliseconds() ?? 0),
|
|
new SqliteParameter("PublishingDate", item.PublishingDate?.ToUnixTimeMilliseconds() ?? 0),
|
|
new SqliteParameter("Authors", item.Authors.Any() ? string.Join(',', item.Authors) : string.Empty),
|
|
new SqliteParameter("Categories", item.Categories.Any() ? string.Join(',', item.Categories) : string.Empty),
|
|
new SqliteParameter("Content", item.Content ?? string.Empty)
|
|
}
|
|
};
|
|
int exec = await cmd.ExecuteNonQueryAsync();*/
|
|
int affected = await dbc.ExecuteAsync(@"INSERT OR REPLACE INTO feed_item (id, feed_url, read, title, description, link, last_updated, publishing_date, authors, categories, content)
|
|
VALUES (@Id, @FeedUrl, @Read, @Title, @Description, @Link, @LastUpdated, @PublishingDate, @Authors, @Categories, @Content)",
|
|
transaction: dbTransaction,
|
|
param: new
|
|
{
|
|
Id = item.Id ?? string.Empty,
|
|
FeedUrl = item.FeedUrl ?? string.Empty,
|
|
Read = item.Read.ToString(),
|
|
Title = item.Title ?? string.Empty,
|
|
Description = item.Description ?? string.Empty,
|
|
Link = item.Link ?? string.Empty,
|
|
LastUpdated = item.LastUpdated?.ToUnixTimeMilliseconds() ?? 0,
|
|
PublishingDate = item.PublishingDate?.ToUnixTimeMilliseconds() ?? 0,
|
|
Authors = item.Authors != null && item.Authors.Any() ? string.Join(',', item.Authors) : string.Empty,
|
|
Categories = item.Categories != null && item.Categories.Any() ? string.Join(',', item.Categories) : string.Empty,
|
|
Content = item.Content ?? string.Empty
|
|
});
|
|
totalAffected += affected;
|
|
}
|
|
dbTransaction.Commit();
|
|
}
|
|
public static async Task<HashSet<FeedItemModel>> GetFeedItemsAsync(string[]? feedUrls)
|
|
{
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
HashSet<FeedItemModel> items = new HashSet<FeedItemModel>();
|
|
await using DbDataReader reader = await dbc.ExecuteReaderAsync(feedUrls == null ? "SELECT * FROM feed_item" : "SELECT * FROM feed_item WHERE feed_item.feed_url IN(@Urls)", new { Urls = feedUrls });
|
|
while (await reader.ReadAsync())
|
|
{
|
|
FeedItemModel feedItemModel = new FeedItemModel()
|
|
{
|
|
Id = reader["id"].ToString(),
|
|
FeedUrl = reader["feed_url"].ToString(),
|
|
Read = bool.Parse(reader["read"].ToString()),
|
|
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()
|
|
};
|
|
items.Add(feedItemModel);
|
|
}
|
|
return items;
|
|
}
|
|
|
|
public static async void Initialize()
|
|
{
|
|
if (_isInitialized) return;
|
|
Log.Verbose("Checking database...");
|
|
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
|
dbc.Open();
|
|
Log.Verbose("Checking table: {Table}", "category");
|
|
await dbc.ExecuteAsync("CREATE TABLE IF NOT EXISTS category (id STRING PRIMARY KEY, name STRING NOT NULL, hex_color STRING NOT NULL, icon STRING)");
|
|
|
|
Log.Verbose("Checking table: {Table}", "feed");
|
|
await dbc.ExecuteAsync("CREATE TABLE IF NOT EXISTS feed (url STRING PRIMARY KEY, title STRING, category_id STRING, feed_type STRING, feed_version STRING, description STRING, language STRING, copyright STRING, publication_date INT, last_updated INT, categories STRING, image_url STRING)");
|
|
|
|
Log.Verbose("Checking table: {Table}", "feed_item");
|
|
await dbc.ExecuteAsync("CREATE TABLE IF NOT EXISTS feed_item (id STRING PRIMARY KEY, feed_url STRING, read STRING, title STRING, description STRING, link STRING, last_updated INT, publishing_date INT, authors STRING, categories STRING, content STRING)");
|
|
Log.Verbose("Checking database done!");
|
|
_isInitialized = true;
|
|
}
|
|
}
|
|
} |