diff --git a/OliverBooth/Data/Blog/BlogPost.cs b/OliverBooth/Data/Blog/BlogPost.cs index cfb1110..05ece19 100644 --- a/OliverBooth/Data/Blog/BlogPost.cs +++ b/OliverBooth/Data/Blog/BlogPost.cs @@ -44,7 +44,7 @@ internal sealed class BlogPost : IBlogPost public DateTimeOffset? Updated { get; internal set; } /// - public BlogPostVisibility Visibility { get; internal set; } + public Visibility Visibility { get; internal set; } /// public int? WordPressId { get; set; } diff --git a/OliverBooth/Data/Blog/Configuration/BlogPostConfiguration.cs b/OliverBooth/Data/Blog/Configuration/BlogPostConfiguration.cs index 7c89b2b..607f9d3 100644 --- a/OliverBooth/Data/Blog/Configuration/BlogPostConfiguration.cs +++ b/OliverBooth/Data/Blog/Configuration/BlogPostConfiguration.cs @@ -26,7 +26,7 @@ internal sealed class BlogPostConfiguration : IEntityTypeConfiguration builder.Property(e => e.DisqusDomain).IsRequired(false); builder.Property(e => e.DisqusIdentifier).IsRequired(false); builder.Property(e => e.DisqusPath).IsRequired(false); - builder.Property(e => e.Visibility).HasConversion(new EnumToStringConverter()).IsRequired(); + builder.Property(e => e.Visibility).HasConversion(new EnumToStringConverter()).IsRequired(); builder.Property(e => e.Password).HasMaxLength(255).IsRequired(false); builder.Property(e => e.Tags).IsRequired() .HasConversion( diff --git a/OliverBooth/Data/Blog/IBlogPost.cs b/OliverBooth/Data/Blog/IBlogPost.cs index a8b9818..d6e4e95 100644 --- a/OliverBooth/Data/Blog/IBlogPost.cs +++ b/OliverBooth/Data/Blog/IBlogPost.cs @@ -85,7 +85,7 @@ public interface IBlogPost /// Gets the visibility of the post. /// /// The visibility of the post. - BlogPostVisibility Visibility { get; } + Visibility Visibility { get; } /// /// Gets the WordPress ID of the post. diff --git a/OliverBooth/Data/Blog/BlogPostVisibility.cs b/OliverBooth/Data/Visibility.cs similarity index 73% rename from OliverBooth/Data/Blog/BlogPostVisibility.cs rename to OliverBooth/Data/Visibility.cs index d8e982a..17b3e87 100644 --- a/OliverBooth/Data/Blog/BlogPostVisibility.cs +++ b/OliverBooth/Data/Visibility.cs @@ -1,10 +1,15 @@ -namespace OliverBooth.Data.Blog; +namespace OliverBooth.Data; /// /// An enumeration of the possible visibilities of a blog post. /// -public enum BlogPostVisibility +public enum Visibility { + /// + /// Used for filtering results. Represents all visibilities. + /// + None = -1, + /// /// The post is private and only visible to the author, or those with the password. /// diff --git a/OliverBooth/Data/Web/Configuration/TutorialArticleConfiguration.cs b/OliverBooth/Data/Web/Configuration/TutorialArticleConfiguration.cs new file mode 100644 index 0000000..56924fd --- /dev/null +++ b/OliverBooth/Data/Web/Configuration/TutorialArticleConfiguration.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace OliverBooth.Data.Web.Configuration; + +/// +/// Represents the configuration for the entity. +/// +internal sealed class TutorialArticleConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("TutorialArticle"); + builder.HasKey(e => e.Id); + + builder.Property(e => e.Id).IsRequired(); + builder.Property(e => e.Folder).IsRequired(); + builder.Property(e => e.Published).IsRequired(); + builder.Property(e => e.Updated); + builder.Property(e => e.Slug).IsRequired(); + builder.Property(e => e.Title).IsRequired(); + builder.Property(e => e.PreviewImageUrl).HasConversion(); + builder.Property(e => e.NextPart); + builder.Property(e => e.PreviousPart); + builder.Property(e => e.Visibility).HasConversion>(); + } +} diff --git a/OliverBooth/Data/Web/Configuration/TutorialFolderConfiguration.cs b/OliverBooth/Data/Web/Configuration/TutorialFolderConfiguration.cs new file mode 100644 index 0000000..af1eef2 --- /dev/null +++ b/OliverBooth/Data/Web/Configuration/TutorialFolderConfiguration.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace OliverBooth.Data.Web.Configuration; + +/// +/// Represents the configuration for the entity. +/// +internal sealed class TutorialFolderConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("TutorialFolder"); + builder.HasKey(e => e.Id); + + builder.Property(e => e.Id).IsRequired(); + builder.Property(e => e.Parent); + builder.Property(e => e.Slug).HasMaxLength(50).IsRequired(); + builder.Property(e => e.Title).HasMaxLength(255).IsRequired(); + builder.Property(e => e.PreviewImageUrl).HasConversion(); + builder.Property(e => e.Visibility).HasConversion>(); + } +} diff --git a/OliverBooth/Data/Web/ITutorialArticle.cs b/OliverBooth/Data/Web/ITutorialArticle.cs new file mode 100644 index 0000000..c1be295 --- /dev/null +++ b/OliverBooth/Data/Web/ITutorialArticle.cs @@ -0,0 +1,73 @@ +namespace OliverBooth.Data.Web; + +/// +/// Represents a tutorial article. +/// +public interface ITutorialArticle +{ + /// + /// Gets the body of this article. + /// + /// The body. + string Body { get; } + + /// + /// Gets the ID of the folder this article is contained within. + /// + /// The ID of the folder. + int Folder { get; } + + /// + /// Gets the ID of this article. + /// + /// The ID. + int Id { get; } + + /// + /// Gets the ID of the next article to this one. + /// + /// The next part ID. + int? NextPart { get; } + + /// + /// Gets the URL of the article's preview image. + /// + /// The preview image URL. + Uri? PreviewImageUrl { get; } + + /// + /// Gets the ID of the previous article to this one. + /// + /// The previous part ID. + int? PreviousPart { get; } + + /// + /// Gets the date and time at which this article was published. + /// + /// The publish timestamp. + DateTimeOffset Published { get; } + + /// + /// Gets the slug of this article. + /// + /// The slug. + string Slug { get; } + + /// + /// Gets the title of this article. + /// + /// The title. + string Title { get; } + + /// + /// Gets the date and time at which this article was updated. + /// + /// The update timestamp, or if this article has not been updated. + DateTimeOffset? Updated { get; } + + /// + /// Gets the visibility of this article. + /// + /// The visibility of the article. + Visibility Visibility { get; } +} diff --git a/OliverBooth/Data/Web/ITutorialFolder.cs b/OliverBooth/Data/Web/ITutorialFolder.cs new file mode 100644 index 0000000..65a3cd2 --- /dev/null +++ b/OliverBooth/Data/Web/ITutorialFolder.cs @@ -0,0 +1,43 @@ +namespace OliverBooth.Data.Web; + +/// +/// Represents a folder for tutorial articles. +/// +public interface ITutorialFolder +{ + /// + /// Gets the ID of this folder. + /// + /// The ID of the folder. + int Id { get; } + + /// + /// Gets the ID of this folder's parent. + /// + /// The ID of the parent, or if this folder is at the root. + int? Parent { get; } + + /// + /// Gets the URL of the folder's preview image. + /// + /// The preview image URL. + Uri? PreviewImageUrl { get; } + + /// + /// Gets the slug of this folder. + /// + /// The slug. + string Slug { get; } + + /// + /// Gets the title of this folder. + /// + /// The title. + string Title { get; } + + /// + /// Gets the visibility of this article. + /// + /// The visibility of the article. + Visibility Visibility { get; } +} diff --git a/OliverBooth/Data/Web/TutorialArticle.cs b/OliverBooth/Data/Web/TutorialArticle.cs new file mode 100644 index 0000000..1938e75 --- /dev/null +++ b/OliverBooth/Data/Web/TutorialArticle.cs @@ -0,0 +1,101 @@ +namespace OliverBooth.Data.Web; + +/// +/// Represents a tutorial article. +/// +internal sealed class TutorialArticle : IEquatable, ITutorialArticle +{ + /// + public string Body { get; private set; } = string.Empty; + + /// + public int Folder { get; private set; } + + /// + public int Id { get; private set; } + + /// + public int? NextPart { get; } + + /// + public Uri? PreviewImageUrl { get; private set; } + + /// + public int? PreviousPart { get; private set; } + + /// + public DateTimeOffset Published { get; private set; } + + /// + public string Slug { get; private set; } = string.Empty; + + /// + public string Title { get; private set; } = string.Empty; + + /// + public DateTimeOffset? Updated { get; private set; } + + /// + public Visibility Visibility { get; private set; } + + /// + /// Returns a value indicating whether two instances of are equal. + /// + /// The first instance of to compare. + /// The second instance of to compare. + /// + /// if and are equal; otherwise, + /// . + /// + public static bool operator ==(TutorialArticle? left, TutorialArticle? right) => Equals(left, right); + + /// + /// Returns a value indicating whether two instances of are not equal. + /// + /// The first instance of to compare. + /// The second instance of to compare. + /// + /// if and are not equal; otherwise, + /// . + /// + public static bool operator !=(TutorialArticle? left, TutorialArticle? right) => !(left == right); + + /// + /// Returns a value indicating whether this instance of is equal to another + /// instance. + /// + /// An instance to compare with this instance. + /// + /// if is equal to this instance; otherwise, + /// . + /// + public bool Equals(TutorialArticle? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Id.Equals(other.Id); + } + + /// + /// Returns a value indicating whether this instance is equal to a specified object. + /// + /// An object to compare with this instance. + /// + /// if is an instance of and + /// equals the value of this instance; otherwise, . + /// + public override bool Equals(object? obj) + { + return ReferenceEquals(this, obj) || obj is TutorialArticle other && Equals(other); + } + + /// + /// Gets the hash code for this instance. + /// + /// The hash code. + public override int GetHashCode() + { + // ReSharper disable once NonReadonlyMemberInGetHashCode + return Id; + } +} diff --git a/OliverBooth/Data/Web/TutorialFolder.cs b/OliverBooth/Data/Web/TutorialFolder.cs new file mode 100644 index 0000000..26c5bc1 --- /dev/null +++ b/OliverBooth/Data/Web/TutorialFolder.cs @@ -0,0 +1,86 @@ +namespace OliverBooth.Data.Web; + +/// +/// Represents a folder for tutorial articles. +/// +internal sealed class TutorialFolder : IEquatable, ITutorialFolder +{ + /// + public int Id { get; private set; } + + /// + public int? Parent { get; private set; } + + /// + public Uri? PreviewImageUrl { get; private set; } + + /// + public string Slug { get; private set; } = string.Empty; + + /// + public string Title { get; private set; } = string.Empty; + + /// + public Visibility Visibility { get; private set; } + + /// + /// Returns a value indicating whether two instances of are equal. + /// + /// The first instance of to compare. + /// The second instance of to compare. + /// + /// if and are equal; otherwise, + /// . + /// + public static bool operator ==(TutorialFolder? left, TutorialFolder? right) => Equals(left, right); + + /// + /// Returns a value indicating whether two instances of are not equal. + /// + /// The first instance of to compare. + /// The second instance of to compare. + /// + /// if and are not equal; otherwise, + /// . + /// + public static bool operator !=(TutorialFolder? left, TutorialFolder? right) => !(left == right); + + /// + /// Returns a value indicating whether this instance of is equal to another + /// instance. + /// + /// An instance to compare with this instance. + /// + /// if is equal to this instance; otherwise, + /// . + /// + public bool Equals(TutorialFolder? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Id.Equals(other.Id); + } + + /// + /// Returns a value indicating whether this instance is equal to a specified object. + /// + /// An object to compare with this instance. + /// + /// if is an instance of and + /// equals the value of this instance; otherwise, . + /// + public override bool Equals(object? obj) + { + return ReferenceEquals(this, obj) || obj is TutorialFolder other && Equals(other); + } + + /// + /// Gets the hash code for this instance. + /// + /// The hash code. + public override int GetHashCode() + { + // ReSharper disable once NonReadonlyMemberInGetHashCode + return Id; + } +} diff --git a/OliverBooth/Data/Web/WebContext.cs b/OliverBooth/Data/Web/WebContext.cs index d5b74e4..8d43e43 100644 --- a/OliverBooth/Data/Web/WebContext.cs +++ b/OliverBooth/Data/Web/WebContext.cs @@ -55,6 +55,18 @@ internal sealed class WebContext : DbContext /// The collection of templates. public DbSet