WIP on F#/RethinkDB conversion
This commit is contained in:
309
src/MyWebLog.Domain/DataTypes.fs
Normal file
309
src/MyWebLog.Domain/DataTypes.fs
Normal file
@@ -0,0 +1,309 @@
|
||||
namespace MyWebLog
|
||||
|
||||
open System
|
||||
|
||||
/// A category under which a post may be identfied
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type Category =
|
||||
{ /// The ID of the category
|
||||
id : CategoryId
|
||||
|
||||
/// The ID of the web log to which the category belongs
|
||||
webLogId : WebLogId
|
||||
|
||||
/// The displayed name
|
||||
name : string
|
||||
|
||||
/// The slug (used in category URLs)
|
||||
slug : string
|
||||
|
||||
/// A longer description of the category
|
||||
description : string option
|
||||
|
||||
/// The parent ID of this category (if a subcategory)
|
||||
parentId : CategoryId option
|
||||
}
|
||||
|
||||
/// Functions to support categories
|
||||
module Category =
|
||||
|
||||
/// An empty category
|
||||
let empty =
|
||||
{ id = CategoryId.empty
|
||||
webLogId = WebLogId.empty
|
||||
name = ""
|
||||
slug = ""
|
||||
description = None
|
||||
parentId = None
|
||||
}
|
||||
|
||||
|
||||
/// A comment on a post
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type Comment =
|
||||
{ /// The ID of the comment
|
||||
id : CommentId
|
||||
|
||||
/// The ID of the post to which this comment applies
|
||||
postId : PostId
|
||||
|
||||
/// The ID of the comment to which this comment is a reply
|
||||
inReplyToId : CommentId option
|
||||
|
||||
/// The name of the commentor
|
||||
name : string
|
||||
|
||||
/// The e-mail address of the commentor
|
||||
email : string
|
||||
|
||||
/// The URL of the commentor's personal website
|
||||
url : string option
|
||||
|
||||
/// The status of the comment
|
||||
status : CommentStatus
|
||||
|
||||
/// When the comment was posted
|
||||
postedOn : DateTime
|
||||
|
||||
/// The text of the comment
|
||||
text : string
|
||||
}
|
||||
|
||||
/// Functions to support comments
|
||||
module Comment =
|
||||
|
||||
/// An empty comment
|
||||
let empty =
|
||||
{ id = CommentId.empty
|
||||
postId = PostId.empty
|
||||
inReplyToId = None
|
||||
name = ""
|
||||
email = ""
|
||||
url = None
|
||||
status = Pending
|
||||
postedOn = DateTime.UtcNow
|
||||
text = ""
|
||||
}
|
||||
|
||||
|
||||
/// A page (text not associated with a date/time)
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type Page =
|
||||
{ /// The ID of this page
|
||||
id : PageId
|
||||
|
||||
/// The ID of the web log to which this page belongs
|
||||
webLogId : WebLogId
|
||||
|
||||
/// The ID of the author of this page
|
||||
authorId : WebLogUserId
|
||||
|
||||
/// The title of the page
|
||||
title : string
|
||||
|
||||
/// The link at which this page is displayed
|
||||
permalink : Permalink
|
||||
|
||||
/// When this page was published
|
||||
publishedOn : DateTime
|
||||
|
||||
/// When this page was last updated
|
||||
updatedOn : DateTime
|
||||
|
||||
/// Whether this page shows as part of the web log's navigation
|
||||
showInPageList : bool
|
||||
|
||||
/// The template to use when rendering this page
|
||||
template : string option
|
||||
|
||||
/// The current text of the page
|
||||
text : string
|
||||
|
||||
/// Permalinks at which this page may have been previously served (useful for migrated content)
|
||||
priorPermalinks : string list
|
||||
|
||||
/// Revisions of this page
|
||||
revisions : Revision list
|
||||
}
|
||||
|
||||
/// Functions to support pages
|
||||
module Page =
|
||||
|
||||
/// An empty page
|
||||
let empty =
|
||||
{ id = PageId.empty
|
||||
webLogId = WebLogId.empty
|
||||
authorId = WebLogUserId.empty
|
||||
title = ""
|
||||
permalink = Permalink.empty
|
||||
publishedOn = DateTime.MinValue
|
||||
updatedOn = DateTime.MinValue
|
||||
showInPageList = false
|
||||
template = None
|
||||
text = ""
|
||||
priorPermalinks = []
|
||||
revisions = []
|
||||
}
|
||||
|
||||
|
||||
/// A web log post
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type Post =
|
||||
{ /// The ID of this post
|
||||
id : PostId
|
||||
|
||||
/// The ID of the web log to which this post belongs
|
||||
webLogId : WebLogId
|
||||
|
||||
/// The ID of the author of this post
|
||||
authorId : WebLogUserId
|
||||
|
||||
/// The status
|
||||
status : PostStatus
|
||||
|
||||
/// The title
|
||||
title : string
|
||||
|
||||
/// The link at which the post resides
|
||||
permalink : Permalink
|
||||
|
||||
/// The instant on which the post was originally published
|
||||
publishedOn : DateTime option
|
||||
|
||||
/// The instant on which the post was last updated
|
||||
updatedOn : DateTime
|
||||
|
||||
/// The text of the post in HTML (ready to display) format
|
||||
text : string
|
||||
|
||||
/// The Ids of the categories to which this is assigned
|
||||
categoryIds : CategoryId list
|
||||
|
||||
/// The tags for the post
|
||||
tags : string list
|
||||
|
||||
/// Permalinks at which this post may have been previously served (useful for migrated content)
|
||||
priorPermalinks : Permalink list
|
||||
|
||||
/// The revisions for this post
|
||||
revisions : Revision list
|
||||
}
|
||||
|
||||
/// Functions to support posts
|
||||
module Post =
|
||||
|
||||
/// An empty post
|
||||
let empty =
|
||||
{ id = PostId.empty
|
||||
webLogId = WebLogId.empty
|
||||
authorId = WebLogUserId.empty
|
||||
status = Draft
|
||||
title = ""
|
||||
permalink = Permalink.empty
|
||||
publishedOn = None
|
||||
updatedOn = DateTime.MinValue
|
||||
text = ""
|
||||
categoryIds = []
|
||||
tags = []
|
||||
priorPermalinks = []
|
||||
revisions = []
|
||||
}
|
||||
|
||||
|
||||
/// A web log
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type WebLog =
|
||||
{ /// The ID of the web log
|
||||
id : WebLogId
|
||||
|
||||
/// The name of the web log
|
||||
name : string
|
||||
|
||||
/// A subtitle for the web log
|
||||
subtitle : string option
|
||||
|
||||
/// The default page ("posts" or a page Id)
|
||||
defaultPage : string
|
||||
|
||||
/// The number of posts to display on pages of posts
|
||||
postsPerPage : int
|
||||
|
||||
/// The path of the theme (within /views/themes)
|
||||
themePath : string
|
||||
|
||||
/// The URL base
|
||||
urlBase : string
|
||||
|
||||
/// The time zone in which dates/times should be displayed
|
||||
timeZone : string
|
||||
}
|
||||
|
||||
/// Functions to support web logs
|
||||
module WebLog =
|
||||
|
||||
/// An empty set of web logs
|
||||
let empty =
|
||||
{ id = WebLogId.empty
|
||||
name = ""
|
||||
subtitle = None
|
||||
defaultPage = ""
|
||||
postsPerPage = 10
|
||||
themePath = "Default"
|
||||
urlBase = ""
|
||||
timeZone = ""
|
||||
}
|
||||
|
||||
/// Convert a permalink to an absolute URL
|
||||
let absoluteUrl webLog = function Permalink link -> $"{webLog.urlBase}{link}"
|
||||
|
||||
|
||||
/// A user of the web log
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type WebLogUser =
|
||||
{ /// The ID of the user
|
||||
id : WebLogUserId
|
||||
|
||||
/// The ID of the web log to which this user belongs
|
||||
webLogId : WebLogId
|
||||
|
||||
/// The user name (e-mail address)
|
||||
userName : string
|
||||
|
||||
/// The user's first name
|
||||
firstName : string
|
||||
|
||||
/// The user's last name
|
||||
lastName : string
|
||||
|
||||
/// The user's preferred name
|
||||
preferredName : string
|
||||
|
||||
/// The hash of the user's password
|
||||
passwordHash : string
|
||||
|
||||
/// Salt used to calculate the user's password hash
|
||||
salt : Guid
|
||||
|
||||
/// The URL of the user's personal site
|
||||
url : string option
|
||||
|
||||
/// The user's authorization level
|
||||
authorizationLevel : AuthorizationLevel
|
||||
}
|
||||
|
||||
/// Functions to support web log users
|
||||
module WebLogUser =
|
||||
|
||||
/// An empty web log user
|
||||
let empty =
|
||||
{ id = WebLogUserId.empty
|
||||
webLogId = WebLogId.empty
|
||||
userName = ""
|
||||
firstName = ""
|
||||
lastName = ""
|
||||
preferredName = ""
|
||||
passwordHash = ""
|
||||
salt = Guid.Empty
|
||||
url = None
|
||||
authorizationLevel = User
|
||||
}
|
||||
13
src/MyWebLog.Domain/MyWebLog.Domain.fsproj
Normal file
13
src/MyWebLog.Domain/MyWebLog.Domain.fsproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="SupportTypes.fs" />
|
||||
<Compile Include="DataTypes.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
181
src/MyWebLog.Domain/SupportTypes.fs
Normal file
181
src/MyWebLog.Domain/SupportTypes.fs
Normal file
@@ -0,0 +1,181 @@
|
||||
namespace MyWebLog
|
||||
|
||||
open System
|
||||
|
||||
/// Support functions for domain definition
|
||||
[<AutoOpen>]
|
||||
module private Helpers =
|
||||
|
||||
/// Create a new ID (short GUID)
|
||||
// https://www.madskristensen.net/blog/A-shorter-and-URL-friendly-GUID
|
||||
let newId() =
|
||||
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace('/', '_').Replace('+', '-')[..22]
|
||||
|
||||
|
||||
/// An identifier for a category
|
||||
type CategoryId = CategoryId of string
|
||||
|
||||
/// Functions to support category IDs
|
||||
module CategoryId =
|
||||
|
||||
/// An empty category ID
|
||||
let empty = CategoryId ""
|
||||
|
||||
/// Convert a category ID to a string
|
||||
let toString = function CategoryId ci -> ci
|
||||
|
||||
/// Create a new category ID
|
||||
let create () = CategoryId (newId ())
|
||||
|
||||
|
||||
/// An identifier for a comment
|
||||
type CommentId = CommentId of string
|
||||
|
||||
/// Functions to support comment IDs
|
||||
module CommentId =
|
||||
|
||||
/// An empty comment ID
|
||||
let empty = CommentId ""
|
||||
|
||||
/// Convert a comment ID to a string
|
||||
let toString = function CommentId ci -> ci
|
||||
|
||||
/// Create a new comment ID
|
||||
let create () = CommentId (newId ())
|
||||
|
||||
|
||||
/// Statuses for post comments
|
||||
type CommentStatus =
|
||||
/// The comment is approved
|
||||
| Approved
|
||||
/// The comment has yet to be approved
|
||||
| Pending
|
||||
/// The comment was unsolicited and unwelcome
|
||||
| Spam
|
||||
|
||||
|
||||
/// The source format for a revision
|
||||
type RevisionSource =
|
||||
/// Markdown text
|
||||
| Markdown
|
||||
/// HTML
|
||||
| Html
|
||||
|
||||
|
||||
/// A revision of a page or post
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type Revision =
|
||||
{ /// When this revision was saved
|
||||
asOf : DateTime
|
||||
|
||||
/// The source language (Markdown or HTML)
|
||||
sourceType : RevisionSource
|
||||
|
||||
/// The text of the revision
|
||||
text : string
|
||||
}
|
||||
|
||||
/// Functions to support revisions
|
||||
module Revision =
|
||||
|
||||
/// An empty revision
|
||||
let empty =
|
||||
{ asOf = DateTime.UtcNow
|
||||
sourceType = Html
|
||||
text = ""
|
||||
}
|
||||
|
||||
|
||||
/// A permanent link
|
||||
type Permalink = Permalink of string
|
||||
|
||||
/// Functions to support permalinks
|
||||
module Permalink =
|
||||
|
||||
/// An empty permalink
|
||||
let empty = Permalink ""
|
||||
|
||||
/// Convert a permalink to a string
|
||||
let toString = function Permalink p -> p
|
||||
|
||||
|
||||
/// An identifier for a page
|
||||
type PageId = PageId of string
|
||||
|
||||
/// Functions to support page IDs
|
||||
module PageId =
|
||||
|
||||
/// An empty page ID
|
||||
let empty = PageId ""
|
||||
|
||||
/// Convert a page ID to a string
|
||||
let toString = function PageId pi -> pi
|
||||
|
||||
/// Create a new page ID
|
||||
let create () = PageId (newId ())
|
||||
|
||||
|
||||
/// Statuses for posts
|
||||
type PostStatus =
|
||||
/// The post should not be publicly available
|
||||
| Draft
|
||||
/// The post is publicly viewable
|
||||
| Published
|
||||
|
||||
|
||||
/// An identifier for a post
|
||||
type PostId = PostId of string
|
||||
|
||||
/// Functions to support post IDs
|
||||
module PostId =
|
||||
|
||||
/// An empty post ID
|
||||
let empty = PostId ""
|
||||
|
||||
/// Convert a post ID to a string
|
||||
let toString = function PostId pi -> pi
|
||||
|
||||
/// Create a new post ID
|
||||
let create () = PostId (newId ())
|
||||
|
||||
|
||||
/// An identifier for a web log
|
||||
type WebLogId = WebLogId of string
|
||||
|
||||
/// Functions to support web log IDs
|
||||
module WebLogId =
|
||||
|
||||
/// An empty web log ID
|
||||
let empty = WebLogId ""
|
||||
|
||||
/// Convert a web log ID to a string
|
||||
let toString = function WebLogId wli -> wli
|
||||
|
||||
/// Create a new web log ID
|
||||
let create () = WebLogId (newId ())
|
||||
|
||||
|
||||
/// A level of authorization for a given web log
|
||||
type AuthorizationLevel =
|
||||
/// <summary>The user may administer all aspects of a web log</summary>
|
||||
| Administrator
|
||||
/// <summary>The user is a known user of a web log</summary>
|
||||
| User
|
||||
|
||||
|
||||
/// An identifier for a web log user
|
||||
type WebLogUserId = WebLogUserId of string
|
||||
|
||||
/// Functions to support web log user IDs
|
||||
module WebLogUserId =
|
||||
|
||||
/// An empty web log user ID
|
||||
let empty = WebLogUserId ""
|
||||
|
||||
/// Convert a web log user ID to a string
|
||||
let toString = function WebLogUserId wli -> wli
|
||||
|
||||
/// Create a new web log user ID
|
||||
let create () = WebLogUserId (newId ())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user