diff --git a/src/snek/docs/__pycache__/app.cpython-312.pyc b/src/snek/docs/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000..6f355a6 Binary files /dev/null and b/src/snek/docs/__pycache__/app.cpython-312.pyc differ diff --git a/src/snek/docs/app.py b/src/snek/docs/app.py new file mode 100644 index 0000000..50a4245 --- /dev/null +++ b/src/snek/docs/app.py @@ -0,0 +1,43 @@ +import pathlib + +from aiohttp import web +from app.app import Application as BaseApplication + +from snek.system.markdown import MarkdownExtension + + +class Application(BaseApplication): + + def __init__(self, path=None, *args, **kwargs): + self.path = pathlib.Path(path) + template_path = self.path + + super().__init__(template_path=template_path, *args, **kwargs) + self.jinja2_env.add_extension(MarkdownExtension) + + self.router.add_get("/{tail:.*}", self.handle_document) + + async def handle_document(self, request): + relative_path = request.match_info["tail"].strip("/") + if relative_path == "": + relative_path = "index.html" + document_path = self.path.joinpath(relative_path) + if not document_path.exists(): + return web.Response( + status=404, + body=b"Resource is not found on this server.", + content_type="text/plain", + ) + if document_path.is_dir(): + document_path = document_path.joinpath("index.html") + if not document_path.exists(): + return web.Response( + status=404, + body=b"Resource is not found on this server.", + content_type="text/plain", + ) + + response = await self.render_template( + str(document_path.relative_to(self.path)), request + ) + return response diff --git a/src/snek/docs/docs/api.html b/src/snek/docs/docs/api.html new file mode 100644 index 0000000..e30a99d --- /dev/null +++ b/src/snek/docs/docs/api.html @@ -0,0 +1,61 @@ +{% extends "docs/base.html" %} + +{% block main %} +{% markdown %} + +# API Documentation + +Currently only some details about the internal API are available. + +## How to create a user +```python +# Save user to the table named 'user' +# Password gets sha256 encrypted with default a salt string +# of the snek.system.security module. + +new_user_object = await app.service.user.register( + username="retoor", + password="retoorded" +) +``` + +## Encrypt string +```python +from snek.system import security + +# Support for both utf and bytes. +var1 = security.encrypt("data") +var2 = security.encrypt(b"data") + +# Is correct: +assert(var1 == var2) +``` + +## How to create a basic HTML / Markdown view +```python +from snek.system.view import BaseView + +class IndexView(BaseView): + + async def get(self): + # The render function supports markdown. + # It will render with syntax highlighting. + # Just use the .md file extension in the file name. + return await self.render("index.html") +``` +## How to create a FormView +```python +from snek.system.view import BaseFormView +from snek.form.register import RegisterForm + +class RegisterFormView(BaseFormView): + + form = RegisterForm +``` +## How to register a class view +```python +app.routes.add_view("/your-page.html", YourViewClass) +``` + +{% endmarkdown %} +{% endblock %} \ No newline at end of file diff --git a/src/snek/docs/docs/base.html b/src/snek/docs/docs/base.html new file mode 100644 index 0000000..7c53bec --- /dev/null +++ b/src/snek/docs/docs/base.html @@ -0,0 +1,116 @@ + + + + + + + + +
+
+ Snek + Docs +
+
+ {% block main %} + {% endblock %} +
+
+ + + + \ No newline at end of file diff --git a/src/snek/docs/docs/form_api_javascript.html b/src/snek/docs/docs/form_api_javascript.html new file mode 100644 index 0000000..c83ee7f --- /dev/null +++ b/src/snek/docs/docs/form_api_javascript.html @@ -0,0 +1,17 @@ +{% extends "docs/base.html" %} + +{% block main %} +{% markdown %} +# Form API Javascript + +## Dependencies + - generic-form.js + +## Usage +It's just a HTML component that can be declared using an one liner. Buttons and title are specified server side. +```html + +``` + +{% endmarkdown %} +{% endblock %} \ No newline at end of file diff --git a/src/snek/docs/docs/form_api_python.html b/src/snek/docs/docs/form_api_python.html new file mode 100644 index 0000000..d7e67bc --- /dev/null +++ b/src/snek/docs/docs/form_api_python.html @@ -0,0 +1,92 @@ +{% extends "docs/base.html" %} + +{% block main %} +{% markdown %} +# Form API Javascript + +## Dependencies + - `snek.system.form.Form` + - `snek.system.form.HTMLElement` + - `snek.system.form.FormInputElement` + - `snek.system.form.FormButtonElement` + +## Usage +Here is an example with custom validation. +This example contains a field that checks if user already exists. +If invalid, it adds an error message which automatically invalidates the field. +Handling of the error messages will automatically done client side. + +Forms are usaly located in `snek/form/[form name].py`. + +```python +from snek.system.form import Form, HTMLElement,FormInputElement,FormButtonElement + +class UsernameField(FormInputElement): + + @property + async def errors(self): + result = await super().errors + if self.value and await self.app.services.user.count(username=self.value): + result.append("Username is not available.") + return result + +class RegisterForm(Form): + + title = HTMLElement(tag="h1", text="Register") + + username = UsernameField( + name="username", + required=True, + min_length=2, + max_length=20, + regex=r"^[a-zA-Z0-9_]+$", + place_holder="Username", + type="text" + ) + email = FormInputElement( + name="email", + required=False, + regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", + place_holder="Email address", + type="email" + ) + password = FormInputElement( + name="password", + required=True, + regex=r"^[a-zA-Z0-9_.+-]{6,}", + type="password", + place_holder="Password" + ) + action = FormButtonElement( + name="action", + value="submit", + text="Register", + type="button" + ) +``` + +## Set data + +```python +# The input structure is in same format as output structure. +# Output structure is the result of await form.to_json() +data = dict( + username=dict(value="retoor"), + password=dict(value="retoorded") +) +form.set_user_data(data) + +# Check if form is valid. +is_valid = await form.is_valid + +# Convert form to a record (kv pairs) to be used for persistance. +# It does contain an filled uid (UUID4) field already to be used as primary key. +# Default fields: +# - uid (automatically generated, it's an UUID4 wich you can use as private key for database) +# - created_at (automatically generated, it's a string representation of UTC locale) +# - updated_at (execute await form.updated_at.update() before saving to set value) +key_value_values = await form.record +``` + +{% endmarkdown %} +{% endblock %} \ No newline at end of file diff --git a/src/snek/docs/docs/index.html b/src/snek/docs/docs/index.html new file mode 100644 index 0000000..8ced8ab --- /dev/null +++ b/src/snek/docs/docs/index.html @@ -0,0 +1,37 @@ +{% extends "docs/base.html" %} + +{% block main %} +{% markdown %} +# Snek + +# Introduction + +Snek is a high customizable chat application. +It is made because Rocket Chat didn't fit my needs anymore. It became bloathed and very heavy commercialized. You would get upsell messages on your locally hosted instance! + +This documentation is under construction. Only the form API and the small introduction is a bit documented. + +## Quick API notes +[Small introduction / cheatsheet](/docs/docs/api.html) + +## View API +With the view classes of Snek you can render HTML and Markdown + - [API Python](#) + - [API Javascript](#) + +## ORM API +Snek's database model is based on Python dataset library. +Snek uses a model/mapper architecture build on top of that library. + - [API](#) + +## Form API +Snek does have his own components for creating and rendering forms. +All forms are made server side and client side is generated client side using a HTML component. +It's client side only one line to include a form that can validate and submit. +Validation is server side using REST. Page won't refresh. +[API Python](/docs/docs/form_api_python.html) +[API Javascript](/docs/docs/form_api_javascript.html) + + +{% endmarkdown %} +{% endblock %} \ No newline at end of file