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