From c8cce33dbfc25e03e623fbb9b1162a122bfaeb08 Mon Sep 17 00:00:00 2001 From: Tim <0xtimc@gmail.com> Date: Thu, 26 Mar 2020 10:12:46 +0000 Subject: [PATCH 1/3] Start updating the README --- README.md | 112 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 10e5cc73..e2ed28dc 100644 --- a/README.md +++ b/README.md @@ -40,40 +40,114 @@ There is an example of how it can work in a site (and what it requires in terms # How to Use +## Add as a dependency -## DOC UPDATES COMING SOON +SteamPress is easy to integrate with your application. There are two providers that provide implementations for [PostgreSQL](https://github.com/brokenhandsio/steampress-fluent-postgres) or [MySQL](https://github.com/brokenhandsio/steampress-fluent-mysql). You are also free to write your own integrations. Normally you'd choose one of the implementations as that provides repository integrations for the database. In this example, we're using Postgres. -**Note:** the `Production` environment will only work on HTTPS for security reasons. +First, add the provider to your `Package.swift` dependencies: -## Integration +```swift +dependencies: [ + // ... + .package(name: "SteampressFluentPostgres", url: "https://github.com/brokenhandsio/steampress-fluent-postgres.git", from: "1.0.0"), +], +``` -In order for SteamPress to work properly, it requires various Middleware to do things like authentication. You must add these to your `droplet.json` so they are loaded up and SteamPress can work properly. In your `droplet.json` add `steampress-sessions` and `blog-persist` like so (and in this order): +Then add it as a dependecy to your application target: -```json -{ - ... - "middleware": [ - ..., - "steampress-sessions" - "blog-persist" - ], - ... -} + +```swift +.target(name: "App", + dependencies: [ + // ... + "SteampressFluentPostgres" + ]) ``` -`steampress-sessions` will used the `Droplet`'s configured `SessionsProtocol` implementation and you can configure it in your `Configuration` (for example to use Redis instead of in-memory). +In `configure.swift`, import the provider: -## Setup +```swift +import SteampressFluentPostgres +``` -SteamPress is easy to integrate with your application. First add SteamPress to your `Package.swift` dependencies: +Next, register the provider with your services: + +```swift +try services.register(SteamPressFluentPostgresProvider()) +``` + +The Provider's require you to add SteamPress' models to your migrations: + +```swift +/// Configure migrations +var migrations = MigrationConfig() +// ... +migrations.add(model: BlogTag.self, database: .psql) +migrations.add(model: BlogUser.self, database: .psql) +migrations.add(model: BlogPost.self, database: .psql) +migrations.add(model: BlogPostTagPivot.self, database: .psql) +// Optional but recommended - this will create an admin user for you to login with +migrations.add(migration: BlogAdminUser.self, database: .psql) +services.register(migrations) +``` + +## Manual Setup + +First add SteamPress to your `Package.swift` dependencies: ```swift dependencies: [ - ..., - .package(url: "https://github.com/brokenhandsio/SteamPress", from: "0.16.0") + // ..., + .package(name: "SteamPress", url: "https://github.com/brokenhandsio/SteamPress", from: "1.0.0") ] ``` +And then as a dependency to your target: + +```swift +.target(name: "App", + dependencies: [ + // ... + "SteamPress" + ]) +``` + +This will register the routes for you. You must provide implementations for the different repository types to your services: + +```swift +services.register(MyTagRepository(), as: BlogTagRepository.self) +services.register(MyUserRepository(), as: BlogUserRepository.self) +services.register(MyPostRepository(), as: BlogPostRepository.self) +``` + +You can then register the SteamPress provider with your services: + +```swift +let steampressProvider = SteamPress.Provider() +try services.register(steampressProvider) +``` + +## Integration + +SteamPress offers a 'Remember Me' functionality when logging in to extend the duration of the session. In order for this to work, you must register the middleware: + +```swift +var middlewares = MiddlewareConfig() +// ... +middlewares.use(BlogRememberMeMiddleware.self) +middlewares.use(SessionsMiddleware.self) +services.register(middlewares) +``` + +**Note:** This must be registered before you register the `SessionsMiddleware`. + +## Configuration + + + + +## Setup + Next import it in the file where you are setting up your `Droplet` with: ```swift From 96dccb6a6987f75d22f2b9bd156d62169ff17ef7 Mon Sep 17 00:00:00 2001 From: Tim <0xtimc@gmail.com> Date: Thu, 26 Mar 2020 11:53:34 +0000 Subject: [PATCH 2/3] More updates --- README.md | 157 +++++++++++++++--------------------------------------- 1 file changed, 43 insertions(+), 114 deletions(-) diff --git a/README.md b/README.md index e2ed28dc..4bd16119 100644 --- a/README.md +++ b/README.md @@ -141,141 +141,72 @@ services.register(middlewares) **Note:** This must be registered before you register the `SessionsMiddleware`. -## Configuration - - - - -## Setup - -Next import it in the file where you are setting up your `Droplet` with: - -```swift -import SteamPress -``` - -Finally, add the provider! - -```swift -try config.addProvider(SteamPress.Provider.self) -``` - -This will look for a config file called `steampress.json` that looks like: - -```json -{ - "postsPerPage": 5, - "blogPath": "blog" -} -``` - -The `blogPath` line is optional, if you want your blog to be at the root path of your site, just remove that line. - -**Note:** you should add the SteamPress Provider before you add the `FluentProvider` to ensure that the password for the admin account is logged out correctly. - -### Manual initialisation - -You can also initialise the Provider manually, by creating it as so: +SteamPress uses a `PasswordVerifier` protocol to check passwords. Vapor doesn't provide a default BCrypt implementation for this, so you must register this yourself: ```swift -let steampress = SteamPress.Provider(postsPerPage: 5) -config.addProvider(steampress) +config.prefer(BCryptDigest.self, for: PasswordVerifier.self) ``` -This will initialise it as the root path of your site. If you wish to have it in a subdirectory, initialise it with: +Finally, if you wish to use the `#markdown()` tag with your blog Leaf templates, you must register this. There's also a paginator tag, to make pagination easy: ```swift -let steampress = SteamPress.Provider(postsPerPage: 5, blogPath: "blog") -config.addProvider(steampress) + var tags = LeafTagConfig.default() +tags.use(Markdown(), as: "markdown") +let paginatorTag = PaginatorTag(paginationLabel: "Blog Posts") +tags.use(paginatorTag, as: PaginatorTag.name) +services.register(tags) ``` -### Bootstrap Versions +## Configuration -By default, the paginator used by SteamPress is expecting to use Bootstrap 4. You can configure it to use Bootstrap 3 by either adding it to the configuration file or the manual initialisation. To add to a config file, in your `steampress.json`, add: +There are a number of configuration options you can pass to the provider to configure SteamPress: -```json -{ - "postsPerPage": 5, - "blogPath": "blog", - "paginator": { - "useBootstrap4": false - } -} -``` +* `blogPath`: the path to add the blog to. By default the blog routes will be registered to the root of your site, but you may want to register the blog at `/blog`. So if you pass in `"blog"` the blog will be available at `https://www.mysite.com/blog`. +* `feedInformation`: Information to vend to the RSS and Atom feeds. +* `postsPerPage`: The number of posts to show per page on the main index page of the blog. Defaults to 10. +* `enableAuthorsPages`: Flag used to determine whether to publicly expose the authors endpoints or not. Defaults to true. +* `enableTagsPages`: Flag used to determine whether to publicy expose the tags endpoints or not. Defaults to true. -To manually iniatialise, set up the Provider like so: +To configure these, you can pass them to the provider. E.g.: ```swift -let steampress = SteamPress.Provider(postsPerPage: 5, blogPath: "blog", useBootstrap4: false) +let feedInformation = FeedInformation( + title: "The SteamPress Blog", + description: "SteamPress is an open-source blogging engine written for Vapor in Swift", + copyright: "Released under the MIT licence", + imageURL: "https://user-images.githubusercontent.com/9938337/29742058-ed41dcc0-8a6f-11e7-9cfc-680501cdfb97.png") +try services.register(SteamPressFluentPostgresProvider(blogPath: "blog", feedInformation: feedInformation, postsPerPage: 5)) ``` -### Disabling Routes - -You can disable the routes for authors pages and tags pages (both individual and all) by adding the option in your configuration file. To disable all of the authors pages, in your `steampress.json` add: - -```json -{ - "enableAuthorsPages": false -} -``` - -To disable all of the tags pages, set: - -```json -{ - "enableTagsPages": false -} -``` - -Both of these settings can also be configured if manually setting up the Provider: - -```swift -let steampress = SteamPress.Provider(postsPerPage:5, enableAuthorsPages: true, enableTagsPages: true) -``` +Additionally, you should set the `WEBSITE_URL` environment variable to the root address of your website, e.g. `https://www.steampress.io`. This is used to set various parameters throughout SteamPress. ## Logging In -When you first launch SteamPress a preparation runs that seeds the database with an admin user. The username is `admin` and the password will be printined out to your app's logs. You will be required to reset your password when you first login. It is recommended you do this as soon as your site is up and running. +When you first launch SteamPress, if you've enabled the `BlogAdminUser` migration, an admin user is created in the database. The username is `admin` and the password will be printined out to your app's logs. It is recommended that you reset your password when you first login as soon as your site is up and running. ## Comments -SteamPress currently supports using [Disqus](https://disqus.com) for the comments engine. To use Disqus, just add a config file `disqus.json` to your site that looks like: - -```json -{ - "disqusName": "NAME_OF_YOUR_DISQUS_SITE" -} -``` - -(You can get the name of your Disqus site from your Disqus admin panel) +SteamPress currently supports using [Disqus](https://disqus.com) for the comments engine. To use Disqus, start the app with the environment variable `BLOG_DISQUS_NAME` set to the name of your disqus sute. (You can get the name of your Disqus site from your Disqus admin panel) -This will pass it through to the Leaf templates for the Blog index (`blog.leaf`), blog posts (`blogpost.leaf`), author page (`profile.leaf`) and tag page (`tag.leaf`) so you can include it if needs be. If you want to manually set up comments you can do this yourself and just include the necessary files for your provider. This is mainly to provide easy configuration for the [Platform site](https://github.com/brokenhandsio/SteamPressExample). +This will pass it through to the Leaf templates for the Blog index (`blog.leaf`), blog posts (`blogpost.leaf`), author page (`profile.leaf`) and tag page (`tag.leaf`) so you can include it if needs be. If you want to manually set up comments you can do this yourself and just include the necessary files for your provider. This is mainly to provide easy configuration for the [example site](https://github.com/brokenhandsio/SteamPressExample). ## Open Graph Twitter Card Support -SteamPress supports both Open Graph and Twitter Cards. The Blog Post `all` Context (see below) will pass in the created date and last edited date (if applicable) in ISO 8601 format for Open Graph article support, under the parameters `create_date_iso8601` and `last_edited_date_iso8601`. +SteamPress supports both Open Graph and Twitter Cards. The blog post page context will pass in the created date and last edited date (if applicable) in ISO 8601 format for Open Graph article support, under the parameters `createdDateNumeric` and `lastEditedDateNumeric`. The Blog Post page will also be passed a number of other useful parameters for Open Graph and Twitter Cards. See the `blogpost.leaf` section below. -The Twitter handle of the site can be configured with a `twitter.json` config file (or injected in) with a property `siteHandle` (the site's twitter handle without the `@`). If set, this will be injected into the public pages as described below. This is for the `twitter:site` tag for Twitter Cards +The Twitter handle of the site can be configured with a `BLOG_SITE_TWITTER_HANDLE` environment variable (the site's twitter handle without the `@`). If set, this will be injected into the public pages as described below. This is for the `twitter:site` tag for Twitter Cards ## Google Analytics Support -SteamPress makes it easy to integrate Google Analytics into your blog. If you create a `googleAnalytics.json` config file that looks like: - -```json -{ - "identifier": "YOUR_IDENTIFIER" -} -``` - -(You can get your identifier from the Google Analytics console, it will look something like UA-12345678-1) +SteamPress makes it easy to integrate Google Analytics into your blog. Just start the application with the `BLOG_GOOGLE_ANALYTICS_IDENTIFIER` environment variable set to you Google Analytics identifier. (You can get your identifier from the Google Analytics console, it will look something like UA-12345678-1) -This will pass a `google_analytics_identifier` parameter through to all of the public pages which you can include and then use the [Example Site's javascript](https://github.com/brokenhandsio/SteamPressExample/blob/master/Public/static/js/analytics.js) to integrate with. +This will pass a `googleAnalyticsIdentifier` parameter through to all of the public pages in the `pageInformation` variable, which you can include and then use the [Example Site's javascript](https://github.com/brokenhandsio/SteamPressExample/blob/master/Public/static/js/analytics.js) to integrate with. ## Atom/RSS Support -SteamPress automatically provides endpoints for registering RSS readers, either using RSS 2.0 or Atom 1.0. These endpoints can be found at the blog's `atom.xml` and `rss.xml` paths; e.g. if you blog is at `https://www.example.com/blog` then the atom feed will appear at `https://wwww.example.com/blog/atom.xml`. These will work by default, but you will probably want to configure some of fields. These can be added to your `steampress.json` config file, with the following values: +SteamPress automatically provides endpoints for registering RSS readers, either using RSS 2.0 or Atom 1.0. These endpoints can be found at the blog's `atom.xml` and `rss.xml` paths; e.g. if you blog is at `https://www.example.com/blog` then the atom feed will appear at `https://wwww.example.com/blog/atom.xml`. These will work by default, but you will probably want to configure some of fields. These are configured with the `FeedInformation` parameter passed to the provider. The configuration options are: * `title` - the title of the blog - a default "SteamPress Blog" will be provided otherwise * `description` - the description of the blog (or subtitle in atom) - a default "SteamPress is an open-source blogging engine written for Vapor in Swift" will be provided otherwise @@ -286,12 +217,19 @@ SteamPress automatically provides endpoints for registering RSS readers, either SteamPress has a built in blog search. It will register a route, `/search`, under your blog path which you can send a query through to, with a key of `term` to search the blog. - # Expected Leaf Templates SteamPress expects there to be a number of Leaf template files in the correct location in `Resources/Views`. All these files should be in a `blog` directory, with the admin template files being in an `admin` directory. For an example of how it SteamPress works with the leaf templates, see the [Example SteamPress site](https://github.com/brokenhandsio/SteamPressExample). -For every Leaf template, a `user` parameter will be passed in for the currently logged in user, if there is a user currently logged in. This is useful for displaying a 'Create Post' link throughout the site when logged in etc. +For every public Leaf template, a `pageInformation` parameter will be passed in with the following information: + +* `disqusName`: The site Disqus name, as discussed above +* `siteTwitterHandle`: The site twitter handle, as discussed above +* `googleAnalyticsIdentifier`: The Google Analytics identifer as discussed above +* `loggedInUser`: The currently logged in user, if a user is logged in. This is useful for displaying a 'Create Post' link throughout the site when logged in etc. +* `websiteURL`: The URL for the website +* `currentPageURL`: The URL of the current page +* `currentPageEncodedURL`: An URL encoded representation of the current page The basic structure of your `Resources/View` directory should be: @@ -503,27 +441,18 @@ let shortSnippet = post.shortSnippet() let longSnippet = post.longSnippet() ``` -# Markdown Provider +# Markdown Tag -The Markdown Provider allows you to render markdown as HTML in your Leaf files. To use, just simply use: +The Markdown Tag allows you to render markdown as HTML in your Leaf files. To use, just simply use: ``` #markdown(myObject.markdownContent) ``` -This will convert the `Node` object `myObject`'s `markdownContent` to HTML (you pass in `myObject` as a parameter to your Leaf view). It uses CommonMark under the hood, but for more details, see the [Markdown Provider repo](https://github.com/vapor-community/markdown-provider). +This will convert the object `myObject`'s `markdownContent` to HTML (you pass in `myObject` as a parameter to your Leaf view). It uses Github Flavoured Markdown under the hood, but for more details, see the [Leaf Markdown repo](https://github.com/vapor-community/leaf-markdown). # API SteamPress also contains an API for accessing certain things that may be useful. The current endpoints are: * `//api/tags/` - returns all the tags that have been saved in JSON - -# Roadmap - -I anticipate SteamPress staying on a version 0 for some time, whilst some of the biggest features are implemented. Semantic versioning makes life a little difficult for this as any new endpoints will require a breaking change for you to add Leaf templates! However, I will aim to stabilise this as quickly as possible, and any breaking changes will be announced in the [releases](https://github.com/brokenhandsio/SteamPress/releases) page. - -On the roadmap we have: - -* AMP/Facebook instant articles endpoints for posts -* Saving state when logging in - if you go to a page (e.g. edit post) but need to be logged in, it would be great if you could head back to that page once logged in. Also, if you have edited a post and your session expires before you post it, wouldn't it be great if it remembered everything! From 5331ee215d7cf9a06dff7c8783a95e1624db371f Mon Sep 17 00:00:00 2001 From: Tim <0xtimc@gmail.com> Date: Thu, 26 Mar 2020 12:38:06 +0000 Subject: [PATCH 3/3] Finish README --- README.md | 210 +++++++++++++++++++++++------------------------------- 1 file changed, 90 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index 4bd16119..294b93aa 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,12 @@ For every public Leaf template, a `pageInformation` parameter will be passed in * `currentPageURL`: The URL of the current page * `currentPageEncodedURL`: An URL encoded representation of the current page +For admin pages, the `pageInformation` parameter has the following information: + +* `loggedInUser`: The currently logged in user, if a user is logged in. This is useful for displaying a 'Create Post' link throughout the site when logged in etc. +* `websiteURL`: The URL for the website +* `currentPageURL`: The URL of the current page + The basic structure of your `Resources/View` directory should be: * `blog` @@ -254,83 +260,87 @@ The basic structure of your `Resources/View` directory should be: This is the index page of the blog. The parameters it will receive are: -* `posts` - a Node containing data about the posts and metadata for the paginator. You can access the posts by calling the `.data` object on it, which is an array of blog posts if there are any, in date descending order. The posts will be made with a `longSnippet` context (see below) -* `tags` - an array of tags if there are any +* `posts` - an array containing `ViewBlogPost`s. This contains all the post information and extra stuff that's useful, such as other date formats and snippets. +* `tags` - an array of `ViewBlogTag`s if there are any * `authors` - an array of the authors if there are any -* `disqus_name` - the name of your Disqus site if configured -* `blog_index_page` - a boolean saying we are on the index page of the blog - useful for navbars -* `site_twitter_handle` - the Twitter handle for the site if configured -* `uri` - the URI of the page - useful for Open Graph -* `google_analytics_identifier` - your Google Analytics identifier if configured - +* `pageInformation` - general page information (see above) +* `title` - the title for the page +* `blogIndexPage` - a boolean saying we are on the index page of the blog - useful for navbars +* `paginationTagInformation` - information for enabling pagination on the page. See `PaginationTagInformation` for more details. ### `blogpost.leaf` This is the page for viewing a single entire blog post. The parameters set are: -* `post` - the full current post, with the `all` context +* `title` - the title of the blog post +* `post` - the blog post as a `ViewBlogPost` * `author` - the author of the post -* `blog_post_page` - a boolean saying we are on the blog post page -* `disqus_name` - the name of your Disqus site if configured -* `post_uri` - The URI of the post -* `post_uri_encoded` - A URL-query encoded for of the URI for passing to Share buttons -* `site_uri`: The URI of the root site - this is useful for creating links to author pages for `article:author` Open Graph support (has a trailing slash) -* `post_description` - The HTML of the short snippet of the post on a single line with all HTML tags stripped out for the `description` tags -* `post_image` - The first image in the blog post if one is there. Useful for OpenGraph and Twitter Cards -* `post_image_alt` - The alt text of the first image if it exists. Useful for Twitter Cards -* `site_twitter_handle` - the Twitter handle for the site if configured -* `google_analytics_identifier` - your Google Analytics identifier if configured +* `blogPostPage` - a boolean saying we are on the blog post page +* `pageInformation` - general page information (see above) +* `postImage` - The first image in the blog post if one is there. Useful for OpenGraph and Twitter Cards +* `postImageAlt` - The alt text of the first image if it exists. Useful for Twitter Cards +* `shortSnippet`: The HTML of the short snippet of the post on a single line with all HTML tags stripped out for the `description` tags ### `tag.leaf` This is the page for a tag. A blog post can be tagged with many tags and a tag can be tagged on many blog posts. This page is generally used for viewing all posts under that tag. The parameters are: * `tag` - the tag -* `posts` - a Node containing data about the posts and metadata for the paginator. You can access the posts by calling the `.data` object on it, which is an array of blog posts if there are any, in date descending order. The posts will be made with a `longSnippet` context (see below) -* `tag_page` - a boolean saying we are on the tag page -* `disqus_name` - the name of your Disqus site if configured -* `site_twitter_handle` - the Twitter handle for the site if configured -* `uri` - the URI of the page - useful for Open Graph -* `google_analytics_identifier` - your Google Analytics identifier if configured +* `posts` - an array of `ViewBlogPost`s that have been tagged with this tag. Note that this may not be all the posts due to pagination +* `tagPage` - a boolean saying we are on the tag page +* `postCount` - the number of posts in total that have this tag +* `pageInformation` - general page information (see above) +* `paginationTagInformation` - information for enabling pagination on the page. See `PaginationTagInformation` for more details. ### `profile.leaf` This is the page for viewing a profile of a user. This is generally used for viewing all posts written by a user, as well as some information about them. The parameters it can have set are: * `author` - the user the page is for -* `profile_page` - a boolean set to to true if we are viewing the profile page -* `posts` - all the posts the user has written if they have written any in `shortSnippet` form -* `disqus_name` - the name of your Disqus site if configured -* `site_twitter_handle` - the Twitter handle for the site if configured -* `uri` - the URI of the page - useful for Open Graph -* `google_analytics_identifier` - your Google Analytics identifier if configured +* `posts` - an array of `ViewBlogPost`s that have been written by this user. Note that this may not be .all the posts due to pagination +* `profilePage` - a boolean set to to true if we are viewing the profile page +* `myProfile` - a boolean set if the currently logged in user is viewing their own profile page +* `postCount` - the number of posts in total that have this tag +* `pageInformation` - general page information (see above) +* `paginationTagInformation` - information for enabling pagination on the page. See `PaginationTagInformation` for more details. ### `tags.leaf` This is the page for viewing all of the tags on the blog. This provides some more navigation points for the blog as well as providing a page in case the user strips off the tag from the Tag's URL. The parameters that can be passed to it are: -* `tags` - an array of all the tags on the blog, in `withPostCount` context (see below) sorted by post count -* `site_twitter_handle` - the Twitter handle for the site if configured -* `uri` - the URI of the page - useful for Open Graph -* `google_analytics_identifier` - your Google Analytics identifier if configured +* `title` - a title for the page +* `tags` - an array of `BlogTagWithPostCount`s. This is the tags with the number of posts tagged with that tag +* `pageInformation` - general page information (see above) ### `authors.leaf` This is the page for viewing all of the authors on the blog. It provides a useful page for user's to see everyone who has contributed to the site. -* `authors` - an array of all the `BlogUser`s on the blog, in `withPostCount` context (see below) sorted by post count -* `site_twitter_handle` - the Twitter handle for the site if configured -* `uri` - the URI of the page - useful for Open Graph -* `google_analytics_identifier` - your Google Analytics identifier if configured +* `authors` - an array of all the `ViewBlogAuthor`s on the blog +* `pageInformation` - general page information (see above) ### `search.leaf` This is the page that will display search results. It has a number of parameters on it on top of the standard parameters: -* `emptySearch` - returned if no search term of an empty search term was received +* `title` - a title for the page * `searchTerm` - the search term if provided -* `searchCount` - the number of results returned from the search -* `posts` - the posts found from the search, paginated, in `longSnippet` form +* `totalResults` - the number of results returned from the search +* `posts` - an array of `ViewBlogPost`s returned in the search. Note that this may not be all the posts due to pagination. +* `pageInformation` - general page information (see above) +* `paginationTagInformation` - information for enabling pagination on the page. See `PaginationTagInformation` for more details. + +### `login.leaf` + +This is the page for logging in to the admin section of the blog. The parameters are: +* `title` - a title for the page +* `errors` - an array of error messages if there were any errors logging in +* `loginWarning` - a flag set if the user tried to access a protected page and was redirected to the login page +* `username` - the username supplied (if any) when originally submitting the login for and there (useful for pre-populating the form) +* `usernameError` - a boolean set if there was an issue with the username +* `passwordError` - a boolean set if there was an error with the password (note that we do not pass any password submitted back to any pages if there was an error for security reasons) +* `rememberMe` - set if the remember me checkbox was checked and there was an error, useful for pre-populating +* `pageInformation` - general page information (see above) ## Admin Site @@ -339,57 +349,61 @@ This is the page that will display search results. It has a number of parameters This is the main Admin page for the blog where you can create and edit users and posts. The parameters for this page are: * `users` - all the users for the site -* `published_posts` - all the posts that have been published if there are any, with the `all` Context -* `draft_posts` - all the draft posts that have been saved but not published, if there are any, with the `all` Context +* `publishedPosts` - all the posts that have been published if there are any, , as `ViewBlogPostWithoutTags` +* `draftPosts` - all the draft posts that have been saved but not published, if there are any, as `ViewBlogPostWithoutTags` * `errors` - any error messages for errors that have occurred when trying to delete posts or users (for instance trying to delete yourself or the last user) -* `blog_admin_page` - a boolean set to true, useful for navigation - -### `login.leaf` - -This is the page for logging in to the admin section of the blog. The parameters are: - -* `username_error` - a boolean set if there was an issue with the username -* `password_error` - a boolean set if there was an error with the password (note that we do not pass any password submitted back to any pages if there was an error for security reasons) -* `username_supplied` - the username supplied (if any) when originally submitting the login for and there (useful for pre-populating the form) -* `errors` - an array of error messages if there were any errors logging in +* `blogAdminPage` - a boolean set to true, useful for navigation +* `title` - the title for the page +* `pageInformation` - general page information as `BlogAdminPageInformation` - see above ### `resetPassword.leaf` This is the page you will be redirected to if you need to reset your password. The parameters are: * `errors` - an array of errors if there were any errors resetting your password -* `password_error` - a boolean set if there was an error with the password (for instance it was blank) -* `confirm_password_error` - a boolean set if there was an error with the password confirm (for instance it was blank) +* `passwordError` - a boolean set if there was an error with the password (for instance it was blank) +* `confirmPasswordError` - a boolean set if there was an error with the password confirm (for instance it was blank) +* `pageInformation` - general page information as `BlogAdminPageInformation` - see above ### `createPost.leaf` This is the page for creating a new blog post, or editing an existing one. The parameters for this page are: -* `title_error` - a boolean set to true if there was an error with the title -* `contents_error` - a boolean set to true if there was an error with the blog contents -* `errors` - an array of error messages if there were any errors creating or editing the blog post -* `title_supplied` - the title of the blog post to edit, or the post that failed to be created -* `contents_supplied` - the contents of the blog post to edit, or the post that failed to be created -* `tags_supplied` - an array of all of the tags that have been specified for the blog post +* `title` - the title for the page * `editing` - a boolean set to true if we are currently editing the a blog post rather than creating a new one * `post` - the post object we are currently editing -* `create_blog_post_page` - a boolean set to true, useful for the navbar etc - -### `createLogin.leaf` +* `draft` - a flag that's set when the post has been saved as a draft +* `errors` - an array of error messages if there were any errors creating or editing the blog post +* `titleSupplied` - the title of the blog post to edit, or the post that failed to be created +* `contentsSupplied` - the contents of the blog post to edit, or the post that failed to be created +* `tagsSupplied` - an array of all of the tags that have been specified for the blog post +* `slugURLSupplied` - the slug URL of the blog post to edit, or the post that failed to be created +* `titleError` - a boolean set to true if there was an error with the title +* `contentsError` - a boolean set to true if there was an error with the blog contents +let postPathPrefix: String +* `postPathPrefix` - the path to the post page that would be created or we are editing +* `pageInformation` - general page information as `BlogAdminPageInformation` - see above + +### `createUser.leaf` This is the page for creating a new user, or editing an existing one. The parameters are: -* `name_error` - a boolean set if there was an error with the name -* `username_error` - a boolean set if there was an error with the username -* `errors` - an array of error messages if there were any errors editing or creating the user -* `name_supplied` - the name of the user we are editing or that we failed to create -* `username_supplied` - the username of the user we are editing or that we failed to create -* `password_error` - a boolean set to true if there was an error with the password -* `confirm_password_error` - a boolean set to true if there was an error with the password confirm -* `reset_password_on_login_supplied` - a boolean set to true if the edit/create submission was asked to reset the users password on next login (this is only supplied in an error so you can pre-populate the form for a user to correct without losing any information) +* `title` - the title for the page * `editing` - a boolean set to true if we are editing a user -* `user_id` - this is the ID of the user if we are editing one. This allows you to send the edit user `POST` back to the correct route - +* `errors` - an array of error messages if there were any errors editing or creating the user +* `nameSupplied` - the name of the user we are editing or that we failed to create +* `nameError` - a boolean set if there was an error with the name +* `usernameSupplied` - the username of the user we are editing or that we failed to create +* `usernameError` - a boolean set if there was an error with the username +* `passwordError` - a boolean set to true if there was an error with the password +* `confirmPasswordError` - a boolean set to true if there was an error with the password confirm +* `resetPasswordOnLoginSupplied` - a boolean set to true if the edit/create submission was asked to reset the users password on next login (this is only supplied in an error so you can pre-populate the form for a user to correct without losing any information) +* `userID` - this is the ID of the user if we are editing one. This allows you to send the edit user `POST` back to the correct route +* `twitterHandleSupplied` - the twitter handle of the user we are editing or that we failed to create +* `profilePictureSupplied` - the URL of the profile picture of the user we are editing or that we failed to create +* `biographySupplied` - the biography of the user we are editing or that we failed to create +* `taglineSupplied` - the tagline of the user we are editing or that we failed to create +* `pageInformation` - general page information as `BlogAdminPageInformation` - see above ## `POST` Routes @@ -397,51 +411,7 @@ There are a number of `POST` routes to the Admin site for creating and editing u This section needs to be filled out, but you can view the Controllers in the code to work out what they should be, or see the [Example Site](https://github.com/brokenhandsio/SteamPressExample). -# Contexts - -## Blog Post - -The blog post has a number of `Context`s you can pass to the `makeNode()` function to provide more information when getting a `BlogPost`. Currently there are three contexts supported: - -* `.shortSnippet` - this will return the post with an `id`, `title`, `author_name`, `author_username`, `slug_url`, `created_date` (Human readable) and `short_snippet` -* `.longSnippet` - this will return the post with an `id`, `title`, `author_name`, `author_username`, `slug_url`, `created_date` (Human readable) and `long_snippet`. It will also include all of the tags in a `tags` object if there are any associated with that post -* `.all` - this returns the post with all information, including both snippet lengths, including author names and human readable dates, as well as both dates in ISO 8601 format under the parameter names `created_date_iso8601` and `last_edited_date_iso8601`. - -If no `Context` is supplied to the `makeNode()` call you will get: - -* `id` -* `title` -* `contents` -* `bloguser_id` - The ID of the Author of the post -* `created` - The time the post was created as a `Double` -* `slug_url` -* `published` - Whether the post has been published or not - -## Blog User - -The blog user has a `withPostCount` `BlogUserContext` available to pass into the `makeNode()` function that provides an extra `post_count` parameter to the user node, which contains the number of posts that author has written. - -## Blog Tag - -The blog user has a `withPostCount` `BlogTagContext` available to pass into the `makeNode()` function that provides an extra `post_count` parameter to the tag node, which contains the number of posts tagged with that tag. - -# Snippets - -SteamPress supports two type of snippets for blog posts - short and long. Short snippets will provide the first paragraph or so of the blog post, whereas long snippets will show several paragraphs (such as for use on the main blog page, when listing all of the posts) - -## Usage - -You can pass in a `BlogPostContext` to the `makeNode()` call to provide more information when getting `BlogPost` objects, as shown above. - -You can also call them directly on a `BlogPost` object (such as from a `Query()`): - -```swift -// These both return the some of the contents of a blog post (as a String) -let shortSnippet = post.shortSnippet() -let longSnippet = post.longSnippet() -``` - -# Markdown Tag +## Markdown Tag The Markdown Tag allows you to render markdown as HTML in your Leaf files. To use, just simply use: