Want to contribute? Fork me on Codeberg.org!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
8.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# soudan
A Rust-based comment server using SQLite and an intuitive REST API. Soudan is built with simplicity and static sites in mind.
## CLI usage
See `soudan --help` for help information.
```
soudan 0.1.0
ElnuDev <elnu@elnu.com>
A Rust-based comment server using SQLite and an intuitive REST API.
USAGE:
soudan [OPTIONS] [CONFIG]
ARGS:
<CONFIG> Set configuration file [default: soudan.yaml]
OPTIONS:
-h, --help Print help information
-p, --port <PORT> Set port where HTTP requests will be received [default: 8080]
-t, --testing Run in testing mode, with in-memory database(s) and permissive CORS policy
-V, --version Print version information
```
Soudan uses a YAML configuration file for most configuration options. By default, this configuration file is `soudan.yaml`, but you can override this by passing in the configuration file path to Soudan as an argument.
For example, to run Soudan on port 8081 with `test.yaml` as the configuration file, use the following command.
```SH
soudan -p 8081 test.yaml
```
In addition, you can add the `-t`/`--testing` flag to run Soudan in testing mode. In this mode, Soudan stores all comments in a fresh in-memory database, and **all comments will be lost once Soudan is closed.** In addition, a permissive CORS policy is used to make testing easier.
### Configuration file
Heres an example configuration file:
```YAML
"localhost:3000":
file: databases/test.db
nameRequired: true
emailRequired: true
"localhost:5000": {}
```
Here, we have two sites, one hosted locally at port 3000 and one hosted locally at port 5000.
For the first site, we specify that we want the SQLite database file to be stored in `databases/test.db`, and we want the name and email fields of each comment to be required to prevent anonymous comments. (Keep in mind that the JavaScript in [soudan.js](demo/soudan.js) assumes that these flags are not set, so you would need to manually add the `required` flag to the name and email `<input>` fields respectively.)
For the second site, we can leave all the configuration fields as their defaults by giving an empty YAML object `{}`. If the database file path isnt provided, it will default to the domain plus the `.db` extension, so in this case it will be `localhost:5000.db` in the current directory. Name and email are not required by default.
## Moderation
Soudan does not have any spam filtering or moderation built in. However, going into the database manually to browse and remove comments is very easy. If you need an SQLite database browser, I'd recommend [DB Browser for SQLite](https://sqlitebrowser.org/).
## API usage
### Fetching comments
Comments can be fetched using a simple GET request to `/{content_id}`, where `content_id` is the content ID of the post set in the page's meta tags. (See [Site configuration](#site-configuration) for information about how to set up your site's HTML to use Soudan.) It is important to note that the content ID is **not unique across sites.** The way the intended site of the request is determined is through the [`Origin` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin). Requests without a valid `Origin` header are rejected. Requests made through the browser will always have this header.
Here is an example API response from real-world usage of Soudan (beautified).
Each comment will have an `id`, `text`, and `timestamp` fields, and optionally an `author` (if absent, comment is anonymous) and a `gravatar` field (the MD5 hash of the commenter's email address. `https://www.gravatar.com/avatar/{gravatar}`). Root level comments will have a `replies` field if replies exist.
```JSON
[
{
"id": 1,
"author": "Elnu",
"gravatar": "1cfb9e38feea40e5150bc0fa69faf693",
"text": "Nice post, me!",
"timestamp": 1658541512,
"replies": [
{
"id": 2,
"author": "Drago",
"text": "HELLO ELNU",
"timestamp": 1658541674
},
{
"id": 3,
"author": "Elnu",
"gravatar": "1cfb9e38feea40e5150bc0fa69faf693",
"text": "HELLO DRAGO",
"timestamp": 1658541732
},
{
"id": 4,
"author": "Drago",
"text": "You should get to drawing ( ͡° ͜ʖ ͡°)",
"timestamp": 1658541778
},
{
"id": 5,
"author": "Elnu",
"gravatar": "1cfb9e38feea40e5150bc0fa69faf693",
"text": "*soon™*",
"timestamp": 1658541863
}
]
}
]
```
### Creating comments
Comments can be likewise created using a simple POST request to `/` (**not** `/{content_id}`).
Here is an example API response from real-world usage of Soudan (beautified).
The request must have a `url` field which is the current page URL. The comment `field` must contain `contentId`, the page content ID (see [Site configuration](#site-configuration)), and `text`. Optionally, the `author`, `email`, and `parent` (the parent comment ID).
```JSON
{
"url": "http://localhost:3000/a/",
"comment": {
"contentId": "a",
"author": "Elnu",
"email": "elnu@elnu.com",
"text": "Test comment",
"parent": null
}
}
```
## Site configuration
Site configuration for Soudan is very straightforward. All you need to do is add the following meta tag to the `<head>` of all pages you want to enable comments on, where you insert your content ID into the `content` attribute of the tag:
```HTML
<meta name="soudan-content-id" content="{content_id}">
```
The content ID can be pretty much anything, provided it's URL-safe (e.g. there must be no forward slashes (`/`)). Spaces are okay, as they will be escaped. A good value to use for the content ID is the slug of your page, as this will be unique and will be obvious what page it is associated with in the database. However, one must make sure that if the page is renamed/moved, either this content ID remains constant or the associated comments are manually updated accordingly in the database (see [Moderation](#moderation)).
### Reference JavaScript client implementation
There is a reference JavaScript client implementation available under [`demo`](demo). It supports Markdown comment rendering via [markdown-it](https://github.com/markdown-it/markdown-it) (images have been disabled) and human-readable relative timestamps for comments via [moment.js](https://momentjs.com/). The icons are from [Heroicons](https://heroicons.com/).
To use it, first add these two dependencies to your page's `<head>`, here using a CDN. You may want to check if there has been a newer version released on cdnjs since the time of writing. ([markdown-it](https://cdnjs.com/libraries/markdown-it), [moment.js](https://cdnjs.com/libraries/moment.js))
```HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.1/markdown-it.min.js" integrity="sha512-SYfDUYPg5xspsG6OOpXU366G8SZsdHOhqk/icdrYJ2E/WKZxPxze7d2HD3AyXpT7U22PZ5y74xRpqZ6A2bJ+kQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
```
The demo HTML pages use the [Sakura CSS framework/theme](https://github.com/oxalorg/sakura) in addition to [a small stylesheet just for Soudan](demo/style.css). Optionally, you can copy this stylesheet into your project. It's pretty theme-agnostic, so it should work fine regardless of your preexisting styles.
```HTML
<link rel="stylesheet" href="/path/to/style.css">
```
Next, copy [soudan.js](demo/soudan.js) into your project. Open it up in your favorite text editor and update the value of `url` [here](https://github.com/ElnuDev/soudan/blob/8b83950f804916e7c14eff4ffd79bb198e0db4bd/demo/soudan.js#L22) to URL of your own Soudan server.
Finally, on each page where you want comments (and where the [meta tag is present](#site-configuration)), add the following container `<div>` and script tag where you want your comment section to be. The comment form, etc. will be automatically generated once your page loads, and **will be hidden if there is a critical error** (i.e. Soudan server offline). **The `<script>` tag must be after the `<div>`.**
```HTML
<div id="soudan"></div>
<script src="/path/to/soudan.js"></script>
```
And... you're done!