Added docks.
This commit is contained in:
		
							parent
							
								
									f9fed90e86
								
							
						
					
					
						commit
						b562d17167
					
				
							
								
								
									
										
											BIN
										
									
								
								src/snek/docs/__pycache__/app.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/snek/docs/__pycache__/app.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										43
									
								
								src/snek/docs/app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/snek/docs/app.py
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										61
									
								
								src/snek/docs/docs/api.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/snek/docs/docs/api.html
									
									
									
									
									
										Normal file
									
								
							| @ -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 %} | ||||||
							
								
								
									
										116
									
								
								src/snek/docs/docs/base.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/snek/docs/docs/base.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | |||||||
|  | <html> | ||||||
|  | 
 | ||||||
|  | <head> | ||||||
|  |     <style>{{ highlight_styles }}</style> | ||||||
|  |     <style> | ||||||
|  |          | ||||||
|  |         * { | ||||||
|  | 
 | ||||||
|  |             box-sizing: border-box; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .dialog { | ||||||
|  | 
 | ||||||
|  |             background-color: #0f0f0f; | ||||||
|  |             border-radius: 10px; | ||||||
|  |             padding: 30px; | ||||||
|  |             width: 800px; | ||||||
|  |             margin: 30px; | ||||||
|  |             box-shadow: 0 0 15px rgba(0, 0, 0, 0.5); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @media screen and (max-width: 500px) { | ||||||
|  |             .center { | ||||||
|  |                 width: 100%; | ||||||
|  |                 left: 0px; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             .dialog { | ||||||
|  |                 width: 100%; | ||||||
|  |                 left: 0px; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h1 { | ||||||
|  |             font-size: 2em; | ||||||
|  |             color: #f05a28; | ||||||
|  |             margin-bottom: 20px; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h2 { | ||||||
|  |             font-size: 1.4em; | ||||||
|  |             color: #f05a28; | ||||||
|  |             margin-bottom: 20px; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         html,body,main { | ||||||
|  |             font-family: Arial, sans-serif; | ||||||
|  |             background-color: #1a1a1a; | ||||||
|  |             color: #e6e6e6; | ||||||
|  |             line-height: 1.5; | ||||||
|  |             display: flex; | ||||||
|  |             flex-direction: column; | ||||||
|  |             align-items: center; | ||||||
|  |             min-height: 100vh; | ||||||
|  |             width: 100%; | ||||||
|  |         } | ||||||
|  |         article { | ||||||
|  |             max-width: 100%; | ||||||
|  |             width: 60%; | ||||||
|  |             background-color: #0f0f0f; | ||||||
|  |             padding: 30px; | ||||||
|  |             min-height: 100vh; | ||||||
|  |             word-break: break-all; | ||||||
|  |         } | ||||||
|  |         footer { | ||||||
|  |             position: fixed; | ||||||
|  |             width: 60%; | ||||||
|  |             text-align: center;  | ||||||
|  |             bottom: 0; | ||||||
|  |             left: 20%; | ||||||
|  |             background-color: #000; | ||||||
|  |         } | ||||||
|  |         a { | ||||||
|  |     color: #f05a28; | ||||||
|  |     display: block; | ||||||
|  |     margin-top: 15px; | ||||||
|  |     font-size: 0.9em; | ||||||
|  |     transition: color 0.3s; | ||||||
|  |   } | ||||||
|  |   header { | ||||||
|  | 
 | ||||||
|  |     text-align: left; | ||||||
|  |     width: 60%; | ||||||
|  |     padding: 30px; | ||||||
|  |   } | ||||||
|  |   header a { | ||||||
|  |     display: inline; | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  |         div { | ||||||
|  |             text-align: left; | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |     </style> | ||||||
|  | </head> | ||||||
|  | 
 | ||||||
|  | <body> | ||||||
|  |     <main> | ||||||
|  |         <header> | ||||||
|  |             <a href="/">Snek</a> | ||||||
|  |             <a href="/docs/docs">Docs</a> | ||||||
|  |         </header> | ||||||
|  |       <article> | ||||||
|  |             {% block main %} | ||||||
|  |             {% endblock %} | ||||||
|  |         </article> | ||||||
|  |     </main> | ||||||
|  |     <footer> | ||||||
|  |         {% markdown %} | ||||||
|  |         [Respository](https://github.com/retoor/snek) | ||||||
|  |         {% endmarkdown %} | ||||||
|  |     </footer> | ||||||
|  | </body> | ||||||
|  | 
 | ||||||
|  | </html> | ||||||
							
								
								
									
										17
									
								
								src/snek/docs/docs/form_api_javascript.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/snek/docs/docs/form_api_javascript.html
									
									
									
									
									
										Normal file
									
								
							| @ -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  | ||||||
|  | <generic-form url="/url-to-form-api"></generic-form> | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | {% endmarkdown %} | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										92
									
								
								src/snek/docs/docs/form_api_python.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/snek/docs/docs/form_api_python.html
									
									
									
									
									
										Normal file
									
								
							| @ -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 %} | ||||||
							
								
								
									
										37
									
								
								src/snek/docs/docs/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/snek/docs/docs/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -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 %} | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user