Backend

Config

The configuration is handled via a .env file. Its fields are documented in the autogenerated API doc for Settings Just place the .env file in the current dir when launching the backend.

A minimal config could be

ADMIN_USERNAME=yourAdminUserName
ADMIN_PASS=yourAdminPassword
SQLALCHEMY_DATABASE_URL=/comments.db

That’s it!

Note

If you’re using the container release version, mount your config file to /.env inside the container

Install

Container

podman run -d -p 8000:80 -v /PATH/TO/CONF:/.env \
    -v /PATH/TO/PERSISTENT_DB/comments.db:/comments.db \
    docker.io/nicocool84/own-comments:latest \
    --proxy-headers \
    --root-path /somewhere  # optional

(you can replace podman with docker here)

PIP

pip install own-comments
uvicorn own_comments.main:app

The easiest way to run the backend is to use a container, but a pypi package is also available if you prefer.

git

Own-comments uses poetry for dependency resolution. Clone the repo and run:

poetry run uvicorn own_comments.main:app --reload

nginx config

server {
    location /somewhere {
        proxy_pass http://127.0.0.1:8000/;
    }
}

OpenAPI schema

For a quick overview of the REST endpoints, you can have a look at the fastapi generated doc on my website.

components:
  schemas:
    Body_create_comment_form_comments_form_post:
      properties:
        author_name:
          title: Author Name
          type: string
        text:
          title: Text
          type: string
      required:
      - author_name
      - text
      title: Body_create_comment_form_comments_form_post
      type: object
    Comment:
      properties:
        approved:
          title: Approved
          type: boolean
        author_name:
          title: Author Name
          type: string
        date_created:
          format: date-time
          title: Date Created
          type: string
        date_updated:
          format: date-time
          title: Date Updated
          type: string
        deleted:
          title: Deleted
          type: boolean
        id:
          title: Id
          type: integer
        text:
          title: Text
          type: string
        thread_id:
          title: Thread Id
          type: integer
        update_key:
          title: Update Key
          type: string
      required:
      - author_name
      - text
      - thread_id
      - id
      - date_created
      - approved
      - deleted
      title: Comment
      type: object
    CommentCreateRequest:
      properties:
        author_name:
          title: Author Name
          type: string
        text:
          title: Text
          type: string
        thread_id:
          title: Thread Id
          type: integer
      required:
      - author_name
      - text
      - thread_id
      title: CommentCreateRequest
      type: object
    CommentCreateResponse:
      properties:
        author_name:
          title: Author Name
          type: string
        date_created:
          format: date-time
          title: Date Created
          type: string
        id:
          title: Id
          type: integer
        text:
          title: Text
          type: string
        thread_id:
          title: Thread Id
          type: integer
        update_key:
          title: Update Key
          type: string
      required:
      - update_key
      - author_name
      - text
      - thread_id
      - id
      - date_created
      title: CommentCreateResponse
      type: object
    CommentDelete:
      properties:
        update_key:
          title: Update Key
          type: string
      title: CommentDelete
      type: object
    CommentPatch:
      properties:
        author_name:
          title: Author Name
          type: string
        text:
          title: Text
          type: string
        update_key:
          title: Update Key
          type: string
      required:
      - author_name
      - text
      title: CommentPatch
      type: object
    HTTPError:
      example:
        detail: HTTPException raised.
      properties:
        detail:
          title: Detail
          type: string
      required:
      - detail
      title: HTTPError
      type: object
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          title: Detail
          type: array
      title: HTTPValidationError
      type: object
    Thread:
      properties:
        auto_approve:
          title: Auto Approve
          type: boolean
        comments:
          default: []
          items:
            $ref: '#/components/schemas/Comment'
          title: Comments
          type: array
        date_created:
          format: date-time
          title: Date Created
          type: string
        id:
          title: Id
          type: integer
        locked:
          title: Locked
          type: boolean
        path:
          title: Path
          type: string
      required:
      - path
      - auto_approve
      - date_created
      - locked
      - id
      title: Thread
      type: object
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          title: Location
          type: array
        msg:
          title: Message
          type: string
        type:
          title: Error Type
          type: string
      required:
      - loc
      - msg
      - type
      title: ValidationError
      type: object
  securitySchemes:
    HTTPBasic:
      scheme: basic
      type: http
info:
  title: FastAPI
  version: 0.1.0
openapi: 3.0.2
paths:
  /auth:
    get:
      description: Verify that admin HTTP basic credentials are valid
      operationId: check_auth_auth_get
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: Successful Response
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
      security:
      - HTTPBasic: []
      summary: Check Auth
  /comments/:
    post:
      description: 'Post a new comment to a specific thread


        Returns the comment with its update key, that should be stored on the author''s

        device for further update or deletion'
      operationId: create_comment_comments__post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CommentCreateRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommentCreateResponse'
          description: Successful Response
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      summary: Create Comment
  /comments/form:
    post:
      description: 'Post a new comment using form data.


        The thread is determined by the path part of the referer HTTP header value.

        Redirects to the commentable page in case of success.'
      operationId: create_comment_form_comments_form_post
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Body_create_comment_form_comments_form_post'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: Successful Response
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      summary: Create Comment Form
  /comments/{comment_id}:
    delete:
      description: 'Mark a comment as deleted.


        Requires either valid admin (HTTP basic) auth or an update key.'
      operationId: delete_comment_comments__comment_id__delete
      parameters:
      - in: path
        name: comment_id
        required: true
        schema:
          title: Comment Id
          type: integer
      - in: query
        name: purge
        required: false
        schema:
          default: false
          title: Purge
          type: boolean
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CommentDelete'
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: Successful Response
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      summary: Delete Comment
    get:
      description: 'Get a specific comment by its ID


        The update key is stripped unless admin is authenticated via HTTP Basic auth'
      operationId: get_comment_comments__comment_id__get
      parameters:
      - in: path
        name: comment_id
        required: true
        schema:
          title: Comment Id
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: Successful Response
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      summary: Get Comment
    patch:
      description: 'Modify a comment.


        Requires either valid admin (HTTP basic) auth or an update key.'
      operationId: patch_comment_comments__comment_id__patch
      parameters:
      - in: path
        name: comment_id
        required: true
        schema:
          title: Comment Id
          type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CommentPatch'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: Successful Response
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      summary: Patch Comment
  /comments/{comment_id}/approve:
    patch:
      description: Approve a comment (admin only).
      operationId: approve_comment_comments__comment_id__approve_patch
      parameters:
      - in: path
        name: comment_id
        required: true
        schema:
          title: Comment Id
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: Successful Response
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      security:
      - HTTPBasic: []
      summary: Approve Comment
  /comments/{comment_id}/unapprove:
    patch:
      description: Unapprove, ie moderate, a comment (admin only).
      operationId: unapprove_comment_comments__comment_id__unapprove_patch
      parameters:
      - in: path
        name: comment_id
        required: true
        schema:
          title: Comment Id
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: Successful Response
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      security:
      - HTTPBasic: []
      summary: Unapprove Comment
  /comments/{comment_id}/undelete:
    patch:
      description: 'Mark a comment as not deleted.


        Requires either valid admin (HTTP basic) auth or an update key.'
      operationId: undelete_comment_comments__comment_id__undelete_patch
      parameters:
      - in: path
        name: comment_id
        required: true
        schema:
          title: Comment Id
          type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CommentDelete'
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: Successful Response
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      summary: Undelete Comment
  /thread_by_path:
    get:
      description: 'Get a thread by its path (ie, location).


        If the thread does not exist yet, it will be created.'
      operationId: get_thread_by_path_thread_by_path_get
      parameters:
      - in: query
        name: path
        required: true
        schema:
          title: Path
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Thread'
          description: Successful Response
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      summary: Get Thread By Path
  /thread_by_referer:
    get:
      description: 'Get a thread by its path, given by the referer HTTP header.


        Used to redirect to the commentable page after no-JS comment post.'
      operationId: get_thread_by_referer_thread_by_referer_get
      responses:
        '307':
          description: Successful Response
      summary: Get Thread By Referer
  /threads/:
    get:
      description: 'Get all threads for this own-comments instance.


        Requires admin auth via HTTP Basic auth.'
      operationId: get_threads_threads__get
      parameters:
      - in: query
        name: skip
        required: false
        schema:
          default: 0
          title: Skip
          type: integer
      - in: query
        name: limit
        required: false
        schema:
          default: 100
          title: Limit
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                items:
                  $ref: '#/components/schemas/Thread'
                title: Response Get Threads Threads  Get
                type: array
          description: Successful Response
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      security:
      - HTTPBasic: []
      summary: Get Threads
  /threads/{thread_id}:
    delete:
      description: 'Deletes a thread and all associated comments


        Requires admin auth via HTTP Basic auth'
      operationId: delete_thread_threads__thread_id__delete
      parameters:
      - in: path
        name: thread_id
        required: true
        schema:
          title: Thread Id
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Thread'
          description: Successful Response
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      security:
      - HTTPBasic: []
      summary: Delete Thread
    get:
      description: 'Get a thread by its thread ID.


        Comment update keys are removed unless valid admin credentials

        are provided via HTTP Basic auth'
      operationId: get_thread_threads__thread_id__get
      parameters:
      - in: path
        name: thread_id
        required: true
        schema:
          title: Thread Id
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Thread'
          description: Successful Response
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      summary: Get Thread
  /threads/{thread_id}/lock:
    patch:
      description: 'Prevent new comments from being posted to a thread


        Requires admin auth via HTTP Basic auth'
      operationId: lock_thread_threads__thread_id__lock_patch
      parameters:
      - in: path
        name: thread_id
        required: true
        schema:
          title: Thread Id
          type: integer
      - in: query
        name: lock
        required: false
        schema:
          default: true
          title: Lock
          type: boolean
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: Successful Response
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Not Found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      security:
      - HTTPBasic: []
      summary: Lock Thread