Clean up database names (#21)

- Moved user edit to "my info" (#19)
This commit is contained in:
2022-07-18 20:05:10 -04:00
parent 5fb3a73dcf
commit 7eaad4a076
36 changed files with 1993 additions and 1745 deletions

View File

@@ -7,22 +7,22 @@ open MyWebLog
[<CLIMutable; NoComparison; NoEquality>]
type Category =
{ /// The ID of the category
id : CategoryId
Id : CategoryId
/// The ID of the web log to which the category belongs
webLogId : WebLogId
WebLogId : WebLogId
/// The displayed name
name : string
Name : string
/// The slug (used in category URLs)
slug : string
Slug : string
/// A longer description of the category
description : string option
Description : string option
/// The parent ID of this category (if a subcategory)
parentId : CategoryId option
ParentId : CategoryId option
}
/// Functions to support categories
@@ -30,12 +30,12 @@ module Category =
/// An empty category
let empty =
{ id = CategoryId.empty
webLogId = WebLogId.empty
name = ""
slug = ""
description = None
parentId = None
{ Id = CategoryId.empty
WebLogId = WebLogId.empty
Name = ""
Slug = ""
Description = None
ParentId = None
}
@@ -43,31 +43,31 @@ module Category =
[<CLIMutable; NoComparison; NoEquality>]
type Comment =
{ /// The ID of the comment
id : CommentId
Id : CommentId
/// The ID of the post to which this comment applies
postId : PostId
PostId : PostId
/// The ID of the comment to which this comment is a reply
inReplyToId : CommentId option
InReplyToId : CommentId option
/// The name of the commentor
name : string
Name : string
/// The e-mail address of the commentor
email : string
Email : string
/// The URL of the commentor's personal website
url : string option
Url : string option
/// The status of the comment
status : CommentStatus
Status : CommentStatus
/// When the comment was posted
postedOn : DateTime
PostedOn : DateTime
/// The text of the comment
text : string
Text : string
}
/// Functions to support comments
@@ -75,15 +75,15 @@ 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 = ""
{ Id = CommentId.empty
PostId = PostId.empty
InReplyToId = None
Name = ""
Email = ""
Url = None
Status = Pending
PostedOn = DateTime.UtcNow
Text = ""
}
@@ -91,43 +91,43 @@ module Comment =
[<CLIMutable; NoComparison; NoEquality>]
type Page =
{ /// The ID of this page
id : PageId
Id : PageId
/// The ID of the web log to which this page belongs
webLogId : WebLogId
WebLogId : WebLogId
/// The ID of the author of this page
authorId : WebLogUserId
AuthorId : WebLogUserId
/// The title of the page
title : string
Title : string
/// The link at which this page is displayed
permalink : Permalink
Permalink : Permalink
/// When this page was published
publishedOn : DateTime
PublishedOn : DateTime
/// When this page was last updated
updatedOn : DateTime
UpdatedOn : DateTime
/// Whether this page shows as part of the web log's navigation
showInPageList : bool
IsInPageList : bool
/// The template to use when rendering this page
template : string option
Template : string option
/// The current text of the page
text : string
Text : string
/// Metadata for this page
metadata : MetaItem list
Metadata : MetaItem list
/// Permalinks at which this page may have been previously served (useful for migrated content)
priorPermalinks : Permalink list
PriorPermalinks : Permalink list
/// Revisions of this page
revisions : Revision list
Revisions : Revision list
}
/// Functions to support pages
@@ -135,19 +135,19 @@ 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 = ""
metadata = []
priorPermalinks = []
revisions = []
{ Id = PageId.empty
WebLogId = WebLogId.empty
AuthorId = WebLogUserId.empty
Title = ""
Permalink = Permalink.empty
PublishedOn = DateTime.MinValue
UpdatedOn = DateTime.MinValue
IsInPageList = false
Template = None
Text = ""
Metadata = []
PriorPermalinks = []
Revisions = []
}
@@ -155,52 +155,52 @@ module Page =
[<CLIMutable; NoComparison; NoEquality>]
type Post =
{ /// The ID of this post
id : PostId
Id : PostId
/// The ID of the web log to which this post belongs
webLogId : WebLogId
WebLogId : WebLogId
/// The ID of the author of this post
authorId : WebLogUserId
AuthorId : WebLogUserId
/// The status
status : PostStatus
Status : PostStatus
/// The title
title : string
Title : string
/// The link at which the post resides
permalink : Permalink
Permalink : Permalink
/// The instant on which the post was originally published
publishedOn : DateTime option
PublishedOn : DateTime option
/// The instant on which the post was last updated
updatedOn : DateTime
UpdatedOn : DateTime
/// The template to use in displaying the post
template : string option
Template : string option
/// The text of the post in HTML (ready to display) format
text : string
Text : string
/// The Ids of the categories to which this is assigned
categoryIds : CategoryId list
CategoryIds : CategoryId list
/// The tags for the post
tags : string list
Tags : string list
/// Podcast episode information for this post
episode : Episode option
Episode : Episode option
/// Metadata for the post
metadata : MetaItem list
Metadata : MetaItem list
/// Permalinks at which this post may have been previously served (useful for migrated content)
priorPermalinks : Permalink list
PriorPermalinks : Permalink list
/// The revisions for this post
revisions : Revision list
Revisions : Revision list
}
/// Functions to support posts
@@ -208,38 +208,38 @@ 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 = ""
template = None
categoryIds = []
tags = []
episode = None
metadata = []
priorPermalinks = []
revisions = []
{ Id = PostId.empty
WebLogId = WebLogId.empty
AuthorId = WebLogUserId.empty
Status = Draft
Title = ""
Permalink = Permalink.empty
PublishedOn = None
UpdatedOn = DateTime.MinValue
Text = ""
Template = None
CategoryIds = []
Tags = []
Episode = None
Metadata = []
PriorPermalinks = []
Revisions = []
}
/// A mapping between a tag and its URL value, used to translate restricted characters (ex. "#1" -> "number-1")
type TagMap =
{ /// The ID of this tag mapping
id : TagMapId
Id : TagMapId
/// The ID of the web log to which this tag mapping belongs
webLogId : WebLogId
WebLogId : WebLogId
/// The tag which should be mapped to a different value in links
tag : string
Tag : string
/// The value by which the tag should be linked
urlValue : string
UrlValue : string
}
/// Functions to support tag mappings
@@ -247,26 +247,26 @@ module TagMap =
/// An empty tag mapping
let empty =
{ id = TagMapId.empty
webLogId = WebLogId.empty
tag = ""
urlValue = ""
{ Id = TagMapId.empty
WebLogId = WebLogId.empty
Tag = ""
UrlValue = ""
}
/// A theme
type Theme =
{ /// The ID / path of the theme
id : ThemeId
Id : ThemeId
/// A long name of the theme
name : string
Name : string
/// The version of the theme
version : string
Version : string
/// The templates for this theme
templates: ThemeTemplate list
Templates: ThemeTemplate list
}
/// Functions to support themes
@@ -274,10 +274,10 @@ module Theme =
/// An empty theme
let empty =
{ id = ThemeId ""
name = ""
version = ""
templates = []
{ Id = ThemeId ""
Name = ""
Version = ""
Templates = []
}
@@ -285,32 +285,42 @@ module Theme =
type ThemeAsset =
{
/// The ID of the asset (consists of theme and path)
id : ThemeAssetId
Id : ThemeAssetId
/// The updated date (set from the file date from the ZIP archive)
updatedOn : DateTime
UpdatedOn : DateTime
/// The data for the asset
data : byte[]
Data : byte[]
}
/// Functions to support theme assets
module ThemeAsset =
/// An empty theme asset
let empty =
{ Id = ThemeAssetId (ThemeId "", "")
UpdatedOn = DateTime.MinValue
Data = [||]
}
/// An uploaded file
type Upload =
{ /// The ID of the upload
id : UploadId
Id : UploadId
/// The ID of the web log to which this upload belongs
webLogId : WebLogId
WebLogId : WebLogId
/// The link at which this upload is served
path : Permalink
Path : Permalink
/// The updated date/time for this upload
updatedOn : DateTime
UpdatedOn : DateTime
/// The data for the upload
data : byte[]
Data : byte[]
}
/// Functions to support uploaded files
@@ -318,11 +328,11 @@ module Upload =
/// An empty upload
let empty = {
id = UploadId.empty
webLogId = WebLogId.empty
path = Permalink.empty
updatedOn = DateTime.MinValue
data = [||]
Id = UploadId.empty
WebLogId = WebLogId.empty
Path = Permalink.empty
UpdatedOn = DateTime.MinValue
Data = [||]
}
@@ -330,40 +340,40 @@ module Upload =
[<CLIMutable; NoComparison; NoEquality>]
type WebLog =
{ /// The ID of the web log
id : WebLogId
Id : WebLogId
/// The name of the web log
name : string
Name : string
/// The slug of the web log
slug : string
Slug : string
/// A subtitle for the web log
subtitle : string option
Subtitle : string option
/// The default page ("posts" or a page Id)
defaultPage : string
DefaultPage : string
/// The number of posts to display on pages of posts
postsPerPage : int
PostsPerPage : int
/// The path of the theme (within /themes)
themePath : string
/// The ID of the theme (also the path within /themes)
ThemeId : ThemeId
/// The URL base
urlBase : string
UrlBase : string
/// The time zone in which dates/times should be displayed
timeZone : string
TimeZone : string
/// The RSS options for this web log
rss : RssOptions
Rss : RssOptions
/// Whether to automatically load htmx
autoHtmx : bool
AutoHtmx : bool
/// Where uploads are placed
uploads : UploadDestination
Uploads : UploadDestination
}
/// Functions to support web logs
@@ -371,29 +381,29 @@ module WebLog =
/// An empty web log
let empty =
{ id = WebLogId.empty
name = ""
slug = ""
subtitle = None
defaultPage = ""
postsPerPage = 10
themePath = "default"
urlBase = ""
timeZone = ""
rss = RssOptions.empty
autoHtmx = false
uploads = Database
{ Id = WebLogId.empty
Name = ""
Slug = ""
Subtitle = None
DefaultPage = ""
PostsPerPage = 10
ThemeId = ThemeId "default"
UrlBase = ""
TimeZone = ""
Rss = RssOptions.empty
AutoHtmx = false
Uploads = Database
}
/// Get the host (including scheme) and extra path from the URL base
let hostAndPath webLog =
let scheme = webLog.urlBase.Split "://"
let scheme = webLog.UrlBase.Split "://"
let host = scheme[1].Split "/"
$"{scheme[0]}://{host[0]}", if host.Length > 1 then $"""/{String.Join ("/", host |> Array.skip 1)}""" else ""
/// Generate an absolute URL for the given link
let absoluteUrl webLog permalink =
$"{webLog.urlBase}/{Permalink.toString permalink}"
$"{webLog.UrlBase}/{Permalink.toString permalink}"
/// Generate a relative URL for the given link
let relativeUrl webLog permalink =
@@ -403,47 +413,47 @@ module WebLog =
/// Convert a UTC date/time to the web log's local date/time
let localTime webLog (date : DateTime) =
TimeZoneInfo.ConvertTimeFromUtc
(DateTime (date.Ticks, DateTimeKind.Utc), TimeZoneInfo.FindSystemTimeZoneById webLog.timeZone)
(DateTime (date.Ticks, DateTimeKind.Utc), TimeZoneInfo.FindSystemTimeZoneById webLog.TimeZone)
/// A user of the web log
[<CLIMutable; NoComparison; NoEquality>]
type WebLogUser =
{ /// The ID of the user
id : WebLogUserId
Id : WebLogUserId
/// The ID of the web log to which this user belongs
webLogId : WebLogId
WebLogId : WebLogId
/// The user name (e-mail address)
userName : string
Email : string
/// The user's first name
firstName : string
FirstName : string
/// The user's last name
lastName : string
LastName : string
/// The user's preferred name
preferredName : string
PreferredName : string
/// The hash of the user's password
passwordHash : string
PasswordHash : string
/// Salt used to calculate the user's password hash
salt : Guid
Salt : Guid
/// The URL of the user's personal site
url : string option
Url : string option
/// The user's access level
accessLevel : AccessLevel
AccessLevel : AccessLevel
/// When the user was created
createdOn : DateTime
CreatedOn : DateTime
/// When the user last logged on
lastSeenOn : DateTime option
LastSeenOn : DateTime option
}
/// Functions to support web log users
@@ -451,27 +461,27 @@ 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
accessLevel = Author
createdOn = DateTime.UnixEpoch
lastSeenOn = None
{ Id = WebLogUserId.empty
WebLogId = WebLogId.empty
Email = ""
FirstName = ""
LastName = ""
PreferredName = ""
PasswordHash = ""
Salt = Guid.Empty
Url = None
AccessLevel = Author
CreatedOn = DateTime.UnixEpoch
LastSeenOn = None
}
/// Get the user's displayed name
let displayName user =
let name =
seq { match user.preferredName with "" -> user.firstName | n -> n; " "; user.lastName }
seq { match user.PreferredName with "" -> user.FirstName | n -> n; " "; user.LastName }
|> Seq.reduce (+)
name.Trim ()
/// Does a user have the required access level?
let hasAccess level user =
AccessLevel.hasAccess level user.accessLevel
AccessLevel.hasAccess level user.AccessLevel