Use file-scoped namespaces

This commit is contained in:
Andriy
2023-07-29 15:14:52 +03:00
parent a24332370d
commit 8ab067a027
58 changed files with 2222 additions and 2280 deletions
+75 -76
View File
@@ -8,83 +8,82 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Kruzya.TelegramBot.RichSiteSummary.Data
namespace Kruzya.TelegramBot.RichSiteSummary.Data;
/// <summary>
/// Represents a feed in database.
/// </summary>
public class Feed : RepresentableEntity
{
/// <summary>
/// Represents a feed in database.
/// </summary>
public class Feed : RepresentableEntity
#region RepresentableEntity
protected override string ViewableText
{
#region RepresentableEntity
protected override string ViewableText
{
get => Title;
}
protected override string ViewableUrl
{
get => HomePage;
}
#endregion
/// <summary>
/// The unique feed id.
/// </summary>
[Key]
public Guid FeedId { get; set; }
/// <summary>
/// The feed URL.
/// </summary>
[Required]
public string Url { get; set; }
/// <summary>
/// The home page for this feed.
/// </summary>
[Required]
public string HomePage { get; set; }
/// <summary>
/// Feed title.
/// </summary>
[MaxLength(256)]
[Required]
public string Title { get; set; }
/// <summary>
/// DateTime when feed fetched successfully in last time.
/// </summary>
[Required]
public DateTime UpdatedAt { get; set; }
/// <summary>
/// This flag indicates, bot should monitor changes in post date, or not.
/// </summary>
[Required]
[DefaultValue(false)]
public bool WatchPostDate { get; set; }
[Required]
[DefaultValue(false)]
public bool IsPrivate { get; set; }
public Feed()
{
FeedId = new Guid();
UpdatedAt = DateTime.Now;
}
/// <summary>
/// All posts from this feed.
/// </summary>
public virtual ICollection<Post> Posts { get; set; }
/// <summary>
/// All exists subscriber for this feed.
/// </summary>
public virtual ICollection<Subscriber> Subscribers { get; set; }
public override string ToString() => Title;
get => Title;
}
protected override string ViewableUrl
{
get => HomePage;
}
#endregion
/// <summary>
/// The unique feed id.
/// </summary>
[Key]
public Guid FeedId { get; set; }
/// <summary>
/// The feed URL.
/// </summary>
[Required]
public string Url { get; set; }
/// <summary>
/// The home page for this feed.
/// </summary>
[Required]
public string HomePage { get; set; }
/// <summary>
/// Feed title.
/// </summary>
[MaxLength(256)]
[Required]
public string Title { get; set; }
/// <summary>
/// DateTime when feed fetched successfully in last time.
/// </summary>
[Required]
public DateTime UpdatedAt { get; set; }
/// <summary>
/// This flag indicates, bot should monitor changes in post date, or not.
/// </summary>
[Required]
[DefaultValue(false)]
public bool WatchPostDate { get; set; }
[Required]
[DefaultValue(false)]
public bool IsPrivate { get; set; }
public Feed()
{
FeedId = new Guid();
UpdatedAt = DateTime.Now;
}
/// <summary>
/// All posts from this feed.
/// </summary>
public virtual ICollection<Post> Posts { get; set; }
/// <summary>
/// All exists subscriber for this feed.
/// </summary>
public virtual ICollection<Subscriber> Subscribers { get; set; }
public override string ToString() => Title;
}
+87 -88
View File
@@ -9,99 +9,98 @@ using System.Text;
using Kruzya.TelegramBot.RichSiteSummary.UrchinTrackingModule;
using Telegram.Bot.Types.Enums;
namespace Kruzya.TelegramBot.RichSiteSummary.Data
namespace Kruzya.TelegramBot.RichSiteSummary.Data;
/// <summary>
/// Represents a post from feed in database.
/// </summary>
public class Post : RepresentableEntity
{
/// <summary>
/// Represents a post from feed in database.
/// </summary>
public class Post : RepresentableEntity
#region RepresentableEntity
protected override ParseMode DefaultRepresentation
{
#region RepresentableEntity
protected override ParseMode DefaultRepresentation
get => ParseMode.Html;
}
protected override string ViewableText
{
get => Title;
}
protected override string ViewableUrl
{
get => UtmUtility.ApplyParameters(new Uri(new(Feed.Url), Url), new UtmParameters()
{
get => ParseMode.Html;
}
Source = "telegram",
Type = "rss_post",
Campaign = "subscriber",
Content = PostId.ToString()
});
}
protected override string ViewableText
#endregion
/// <summary>
/// The unique post id.
/// </summary>
[Key]
public Guid PostId { get; set; }
/// <summary>
/// The feed unique identifier from where this post is fetched.
/// </summary>
public Guid FeedId { get; set; }
/// <summary>
/// The feed from where this post is fetched.
/// </summary>
[Required]
public virtual Feed Feed { get; set; }
/// <summary>
/// The post title.
/// </summary>
[MaxLength(256)]
[Required]
public string Title { get; set; }
/// <summary>
/// The URI where this post is located in web.
/// </summary>
[Required]
[MaxLength(256)]
public string Url { get; set; }
/// <summary>
/// DateTime when post is created in RSS feed.
/// </summary>
[Required]
public DateTime PostedAt { get; set; }
/// <summary>
/// DateTime when post is fetched/updated in database.
/// </summary>
[Required]
public DateTime ReceivedAt { get; set; }
public Post()
{
PostId = new Guid();
ReceivedAt = DateTime.Now;
}
public string MessageText
{
get
{
get => Title;
}
protected override string ViewableUrl
{
get => UtmUtility.ApplyParameters(new Uri(new(Feed.Url), Url), new UtmParameters()
{
Source = "telegram",
Type = "rss_post",
Campaign = "subscriber",
Content = PostId.ToString()
});
}
#endregion
/// <summary>
/// The unique post id.
/// </summary>
[Key]
public Guid PostId { get; set; }
/// <summary>
/// The feed unique identifier from where this post is fetched.
/// </summary>
public Guid FeedId { get; set; }
/// <summary>
/// The feed from where this post is fetched.
/// </summary>
[Required]
public virtual Feed Feed { get; set; }
/// <summary>
/// The post title.
/// </summary>
[MaxLength(256)]
[Required]
public string Title { get; set; }
/// <summary>
/// The URI where this post is located in web.
/// </summary>
[Required]
[MaxLength(256)]
public string Url { get; set; }
/// <summary>
/// DateTime when post is created in RSS feed.
/// </summary>
[Required]
public DateTime PostedAt { get; set; }
/// <summary>
/// DateTime when post is fetched/updated in database.
/// </summary>
[Required]
public DateTime ReceivedAt { get; set; }
public Post()
{
PostId = new Guid();
ReceivedAt = DateTime.Now;
}
public string MessageText
{
get
{
var message = new StringBuilder();
message.Append($"{Representation("🗞")} New on {Feed.Representation(ParseMode.Html)}\n");
message.Append("\n");
message.Append(Title);
message.Append("\n");
message.Append(Representation("Open in browser"));
var message = new StringBuilder();
message.Append($"{Representation("🗞")} New on {Feed.Representation(ParseMode.Html)}\n");
message.Append("\n");
message.Append(Title);
message.Append("\n");
message.Append(Representation("Open in browser"));
return message.ToString();
}
return message.ToString();
}
}
}
}
@@ -7,55 +7,54 @@ using System;
using System.Web;
using Telegram.Bot.Types.Enums;
namespace Kruzya.TelegramBot.RichSiteSummary.Data
namespace Kruzya.TelegramBot.RichSiteSummary.Data;
/// <summary>
/// Implements the basic logic for rendering Database Entities in messages.
/// </summary>
public abstract class RepresentableEntity
{
/// <summary>
/// Implements the basic logic for rendering Database Entities in messages.
/// </summary>
public abstract class RepresentableEntity
protected virtual string ViewableText { get; }
protected virtual string ViewableUrl { get; }
protected virtual ParseMode DefaultRepresentation { get; }
public override string ToString() => Representation();
public string Representation(string text) => Representation(DefaultRepresentation, text);
public string Representation() => Representation(DefaultRepresentation);
public string Representation(ParseMode parseMode) => Representation(parseMode, ViewableText);
public string Representation(ParseMode parseMode, string text)
{
protected virtual string ViewableText { get; }
protected virtual string ViewableUrl { get; }
protected virtual ParseMode DefaultRepresentation { get; }
public override string ToString() => Representation();
public string Representation(string text) => Representation(DefaultRepresentation, text);
public string Representation() => Representation(DefaultRepresentation);
public string Representation(ParseMode parseMode) => Representation(parseMode, ViewableText);
public string Representation(ParseMode parseMode, string text)
string content = String.Empty;
switch (parseMode)
{
string content = String.Empty;
switch (parseMode)
{
case ParseMode.Html:
content = HtmlRepresentation(text);
break;
case ParseMode.Html:
content = HtmlRepresentation(text);
break;
case ParseMode.Markdown:
case ParseMode.MarkdownV2:
throw new NotImplementedException();
}
return content;
case ParseMode.Markdown:
case ParseMode.MarkdownV2:
throw new NotImplementedException();
}
#region Representations
public string RawRepresentation(string text)
=> text;
public string HtmlRepresentation(string text)
{
var escapedText = HttpUtility.HtmlEncode(text);
var escapedUrl = HttpUtility.HtmlAttributeEncode(ViewableUrl);
return $"<a href=\"{escapedUrl}\">{escapedText}</a>";
}
#endregion
return content;
}
#region Representations
public string RawRepresentation(string text)
=> text;
public string HtmlRepresentation(string text)
{
var escapedText = HttpUtility.HtmlEncode(text);
var escapedUrl = HttpUtility.HtmlAttributeEncode(ViewableUrl);
return $"<a href=\"{escapedUrl}\">{escapedText}</a>";
}
#endregion
}
@@ -1,58 +1,57 @@
using Kruzya.TelegramBot.Core.EF;
using Microsoft.EntityFrameworkCore;
namespace Kruzya.TelegramBot.RichSiteSummary.Data
namespace Kruzya.TelegramBot.RichSiteSummary.Data;
public class RichSiteSummaryContext : AutoSaveDbContext
{
public class RichSiteSummaryContext : AutoSaveDbContext
/// <summary>
/// Repository with all feeds in database.
/// </summary>
public DbSet<Feed> Feeds { get; set; }
/// <summary>
/// Repository with all posts in database.
/// </summary>
public DbSet<Post> Posts { get; set; }
/// <summary>
/// Repository with all subscriptions in database.
/// </summary>
public DbSet<Subscriber> Subscriptions { get; set; }
/// <summary>
/// Ensures the database is created and calls parent constructor.
/// </summary>
/// <param name="options"></param>
public RichSiteSummaryContext(DbContextOptions<RichSiteSummaryContext> options) : base(options)
{
/// <summary>
/// Repository with all feeds in database.
/// </summary>
public DbSet<Feed> Feeds { get; set; }
/// <summary>
/// Repository with all posts in database.
/// </summary>
public DbSet<Post> Posts { get; set; }
/// <summary>
/// Repository with all subscriptions in database.
/// </summary>
public DbSet<Subscriber> Subscriptions { get; set; }
Database.EnsureCreated();
}
/// <summary>
/// Ensures the database is created and calls parent constructor.
/// </summary>
/// <param name="options"></param>
public RichSiteSummaryContext(DbContextOptions<RichSiteSummaryContext> options) : base(options)
{
Database.EnsureCreated();
}
/// <summary>
/// Setup the additional unique keys.
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Setup unique keys for Feed entity.
modelBuilder.Entity<Feed>().HasIndex(feed => feed.Url).IsUnique();
modelBuilder.Entity<Feed>().HasIndex(feed => feed.HomePage).IsUnique();
/// <summary>
/// Setup the additional unique keys.
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Setup unique keys for Feed entity.
modelBuilder.Entity<Feed>().HasIndex(feed => feed.Url).IsUnique();
modelBuilder.Entity<Feed>().HasIndex(feed => feed.HomePage).IsUnique();
// Setup unique keys for Post entity.
modelBuilder.Entity<Post>()
.HasOne(p => p.Feed)
.WithMany(f => f.Posts)
.HasForeignKey(p => p.FeedId);
// Setup unique keys for Post entity.
modelBuilder.Entity<Post>()
.HasOne(p => p.Feed)
.WithMany(f => f.Posts)
.HasForeignKey(p => p.FeedId);
modelBuilder.Entity<Post>().HasIndex(post =>
new {post.FeedId, post.Url}).IsUnique();
modelBuilder.Entity<Post>().HasIndex(post =>
new {post.FeedId, post.Url}).IsUnique();
// Setup foreign keys for Subscriber entity.
modelBuilder.Entity<Subscriber>()
.HasOne(s => s.Feed)
.WithMany(f => f.Subscribers)
.HasForeignKey(s => s.FeedId);
}
// Setup foreign keys for Subscriber entity.
modelBuilder.Entity<Subscriber>()
.HasOne(s => s.Feed)
.WithMany(f => f.Subscribers)
.HasForeignKey(s => s.FeedId);
}
}
+40 -41
View File
@@ -6,51 +6,50 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace Kruzya.TelegramBot.RichSiteSummary.Data
namespace Kruzya.TelegramBot.RichSiteSummary.Data;
/// <summary>
/// Represents a subscription in database.
/// </summary>
public class Subscriber
{
/// <summary>
/// Represents a subscription in database.
/// The unique Subscription identifier.
/// </summary>
public class Subscriber
[Key]
public Guid SubscriptionId { get; set; }
/// <summary>
/// The Telegram subscriber id.
/// </summary>
[Required]
public Int64 SubscriberId { get; set; }
/// <summary>
/// Unique feed identifier related with this Subscription. Identifies what user is read.
/// </summary>
public Guid FeedId { get; set; }
/// <summary>
/// Feed related with this Subscription. Identifies what user is read.
/// </summary>
[Required]
public virtual Feed Feed { get; set; }
/// <summary>
/// When user is subscribed on this feed.
/// </summary>
[Required]
public DateTime SubscribedAt { get; set; }
public Subscriber()
{
/// <summary>
/// The unique Subscription identifier.
/// </summary>
[Key]
public Guid SubscriptionId { get; set; }
/// <summary>
/// The Telegram subscriber id.
/// </summary>
[Required]
public Int64 SubscriberId { get; set; }
/// <summary>
/// Unique feed identifier related with this Subscription. Identifies what user is read.
/// </summary>
public Guid FeedId { get; set; }
/// <summary>
/// Feed related with this Subscription. Identifies what user is read.
/// </summary>
[Required]
public virtual Feed Feed { get; set; }
SubscriptionId = new Guid();
SubscribedAt = DateTime.Now;
}
/// <summary>
/// When user is subscribed on this feed.
/// </summary>
[Required]
public DateTime SubscribedAt { get; set; }
public Subscriber()
{
SubscriptionId = new Guid();
SubscribedAt = DateTime.Now;
}
public Subscriber(Feed feed) : base()
{
Feed = feed;
}
public Subscriber(Feed feed) : base()
{
Feed = feed;
}
}