### Deploy Otter Wiki with Helm CLI arguments Source: https://github.com/redimp/otterwiki/blob/main/helm/README.md Use the --set flag to override default configuration values during installation. ```bash helm install my-otterwiki \ --set config.SITE_DESCRIPTION="An Otter Wiki deployed with Helm" \ --set ingress.enabled=true \ --set ingress.hosts[0].host="helm.otterwiki.com" \ --version 0.1.0 \ otterwiki/otterwiki ``` -------------------------------- ### Deploy Otter Wiki using a values file Source: https://github.com/redimp/otterwiki/blob/main/helm/README.md Apply the configuration defined in a local values.yaml file during the Helm installation. ```bash helm install my-otterwiki \ --values values.yaml \ --version 0.1.0 \ otterwiki/otterwiki ``` -------------------------------- ### Install An Otter Wiki Helm Chart Source: https://github.com/redimp/otterwiki/blob/main/helm/README.md Installs An Otter Wiki on your Kubernetes cluster using the specified release name and chart version. This deploys the wiki with default configurations. ```bash helm install my-otterwiki --version 0.1.0 otterwiki/otterwiki ``` -------------------------------- ### Interact with REST API Endpoints Source: https://context7.com/redimp/otterwiki/llms.txt Examples of using curl to access wiki health checks, feeds, webhooks, and Git operations. ```bash # Health check endpoint curl http://localhost:8080/-/healthz # Returns: "OK" with 200, or error with 503 # Changelog RSS/Atom feeds curl http://localhost:8080/-/changelog/feed.rss curl http://localhost:8080/-/changelog/feed.atom # Sitemap for search engines curl http://localhost:8080/-/sitemap.xml # Git webhook for automatic pulls (when configured) # The hash is SHA-256 of (remote_url + 'otterwiki') curl -X POST http://localhost:8080/-/api/v1/pull/ # Page source (raw markdown) curl "http://localhost:8080/PageName/source?raw" # Git HTTP server (when GIT_WEB_SERVER=True) git clone http://localhost:8080/.git wiki-content cd wiki-content # Make changes... git push origin main ``` -------------------------------- ### Add OtterWiki Helm Repository Source: https://github.com/redimp/otterwiki/blob/main/helm/README.md Adds the OtterWiki Helm repository to your local configuration. This command is necessary before you can install the OtterWiki chart. ```bash helm repo add otterwiki https://charts.otterwiki.com helm repo update ``` -------------------------------- ### Get Application URL for LoadBalancer Service Source: https://github.com/redimp/otterwiki/blob/main/helm/templates/NOTES.txt Use these commands to retrieve the application URL for a LoadBalancer service. Note that it may take a few minutes for the LoadBalancer IP to become available. You can monitor its status with 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "otterwiki.fullname" . }}'. ```bash export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "otterwiki.fullname" . }} --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}") echo http://$SERVICE_IP:{{ .Values.service.port }} ``` -------------------------------- ### Get Application URL for NodePort Service Source: https://github.com/redimp/otterwiki/blob/main/helm/templates/NOTES.txt Run these commands to get the application URL when the service type is NodePort. It exports the NodePort and Node IP to construct the URL. ```bash export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "otterwiki.fullname" . }}) export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT ``` -------------------------------- ### Configure Plugin Entry Point Source: https://context7.com/redimp/otterwiki/llms.txt Registers the plugin in the pyproject.toml file to make it discoverable by OtterWiki. ```toml [project] name = "otterwiki-myplugin" version = "1.0.0" [project.entry-points.otterwiki] myplugin = "otterwiki_myplugin:MyPlugin" ``` -------------------------------- ### Define Python route and class structure Source: https://github.com/redimp/otterwiki/blob/main/tests/example.md Demonstrates a Flask-style route for serving a favicon and a basic class definition. ```python @app.route("/favicon.ico") def favicon(): return send_from_directory( os.path.join(app.root_path, "static/img"), "favicon.ico", mimetype="image/vnd.microsoft.icon", ) class SomeClass: pass >>> message = '''interpreter ... prompt''' ``` -------------------------------- ### Creating Tables Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Syntax for defining tables using pipes and dashes. ```markdown | Column 1 | Column 2 | Column 3 | | -------- | -------- | -------- | | John | Doe | Peach | | Mary | Smith | Banana | ``` -------------------------------- ### Define Otter Wiki configuration in values.yaml Source: https://github.com/redimp/otterwiki/blob/main/helm/README.md Create a YAML file to manage complex configuration settings for the deployment. ```yaml config: SITE_DESCRIPTION: "An Otter Wiki deployed with Helm" ingress: enabled: true hosts: - helm.otterwiki.com ``` -------------------------------- ### Deploy An Otter Wiki with Docker Compose Source: https://github.com/redimp/otterwiki/blob/main/README.md Use this configuration to run the Otter Wiki container. Ensure the volume path is mapped correctly to your local storage. ```yaml services: otterwiki: image: redimp/otterwiki:2 restart: unless-stopped ports: - 8080:80 volumes: - ./app-data:/app-data ``` -------------------------------- ### Creating Headings Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Syntax for different levels of headings using hashes or underline styles. ```markdown # h1 - Large header ``` ```markdown ## h2 - Medium header ``` ```markdown ### h3 - Small header ``` ```markdown #### h4 - Tiny header ``` -------------------------------- ### Creating Lists Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Syntax for unordered and ordered lists, including nested structures. ```markdown - Generic list items - in an unordered list ``` ```markdown 1. List items 2. in an ordered list 3. numbered with numbers ``` ```markdown 1. Numbered list with - a nested - unordered list 2. inside ``` ```markdown - First list - of items * Second list * of items ``` -------------------------------- ### Initialize Mermaid with Theme Support Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/renderer_js.html Initializes the Mermaid library upon DOM content loading, automatically detecting the current dark mode status to set the theme. ```javascript document.addEventListener("DOMContentLoaded", function(event) { let theme = 'neutral'; if (document.querySelector("body").classList.contains("dark-mode")) { theme = 'dark'; } mermaid.initialize({ theme: theme, }); }); ``` -------------------------------- ### Adding Links Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Syntax for internal WikiLinks and external URLs. ```markdown [[WikiPage]] ``` ```markdown [[WikiPage|Text to display]] ``` ```markdown http://www.example.com ``` ```markdown [Link with text](http://example.com) ``` -------------------------------- ### Docker Compose Deployment for Otter Wiki Source: https://context7.com/redimp/otterwiki/llms.txt Deploy Otter Wiki using Docker Compose. Ensure persistent storage for wiki data. The first registered user automatically becomes an administrator. ```yaml # docker-compose.yml services: otterwiki: image: redimp/otterwiki:2 restart: unless-stopped ports: - 8080:80 volumes: - ./app-data:/app-data environment: # Generate a random secret key for production - SECRET_KEY=your-random-secret-key-at-least-16-chars - SITE_NAME=My Wiki # Access control: ANONYMOUS, REGISTERED, or APPROVED - READ_ACCESS=ANONYMOUS - WRITE_ACCESS=REGISTERED - ATTACHMENT_ACCESS=REGISTERED ``` ```bash # Start the wiki docker-compose up -d # Access at http://localhost:8080 # First registered user becomes admin ``` -------------------------------- ### Access An Otter Wiki via Ingress Source: https://github.com/redimp/otterwiki/blob/main/helm/templates/NOTES.txt Use this when Ingress is enabled. It lists the hostnames to access the application. ```go-template {{- if .Values.ingress.enabled }} Open up your installation of An Otter Wiki via {{ range $host := .Values.ingress.hosts }} http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }} {{- end }} {{- end }} ``` -------------------------------- ### Manage Users via CLI Source: https://context7.com/redimp/otterwiki/llms.txt Use Flask CLI commands to perform user management tasks such as listing, creating, editing, and deleting users. ```bash # List all users flask user list flask user list --json # Create a new user flask user create user@example.com "John Doe" flask user create admin@example.com "Admin User" -p admin flask user create user@example.com "Jane" --flags=email_confirmed,approved --permissions=read,write # Edit user flask user edit user@example.com --new-name="Jane Doe" flask user edit user@example.com --new-email=newemail@example.com flask user edit user@example.com --flags=email_confirmed,approved flask user edit user@example.com --permissions=read,write,upload # Password management flask user password user@example.com --interactive # Prompt for password flask user password user@example.com --generate # Generate random password flask user password user@example.com --send-password-reset # Send reset email flask user password user@example.com --delete # Remove password (disable login) # Delete user flask user delete user@example.com flask user delete user@example.com --confirm # Skip confirmation prompt ``` -------------------------------- ### Plugin System Source: https://context7.com/redimp/otterwiki/llms.txt Information on extending OtterWiki functionality using its pluggy-based hook system. ```APIDOC ## Plugin System Create plugins using the pluggy-based hook system to extend wiki functionality. ```python # Plugin development examples would go here. ``` ``` -------------------------------- ### Fetch default values.yaml Source: https://github.com/redimp/otterwiki/blob/main/helm/README.md Retrieve the default configuration file for a specific chart version. ```bash helm show values --version 0.1.0 otterwiki/otterwiki > values.yaml ``` -------------------------------- ### Otter Wiki Configuration Settings Source: https://context7.com/redimp/otterwiki/llms.txt Configure Otter Wiki using environment variables or a settings.cfg file. Key settings include secret key, site name, access permissions, user registration, database URI, and mail server details. ```python # settings.cfg - Core configuration options DEBUG = False SECRET_KEY = 'your-secret-key-at-least-16-characters' SITE_NAME = 'My Otter Wiki' REPOSITORY = '/path/to/git/repository' # Optional: Custom logo (can be an attachment URL) SITE_LOGO = '/Home/a/logo.png' # Permission levels: ANONYMOUS, REGISTERED, or APPROVED READ_ACCESS = 'ANONYMOUS' # Who can read pages WRITE_ACCESS = 'REGISTERED' # Who can edit pages ATTACHMENT_ACCESS = 'REGISTERED' # Who can upload files # User registration settings AUTO_APPROVAL = True # Auto-approve new users EMAIL_NEEDS_CONFIRMATION = True # Require email verification DISABLE_REGISTRATION = False # Disable new registrations # Database (SQLite by default) SQLALCHEMY_DATABASE_URI = 'sqlite:////app-data/db.sqlite' # Mail server for notifications MAIL_SERVER = 'smtp.example.com' MAIL_PORT = 587 MAIL_USE_TLS = True MAIL_USERNAME = 'wiki@example.com' MAIL_PASSWORD = 'mail-password' MAIL_DEFAULT_SENDER = 'wiki@example.com' ``` -------------------------------- ### Generate Image Thumbnails Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/help.md Syntax for generating thumbnails or resizing images using URL parameters. ```markdown ![](/page/attachment.jpg?thumbnail) ``` ```markdown ?thumbnail=400 ``` -------------------------------- ### Render Sidebar Shortcuts Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/admin/sidebar_preferences.html Iterates through a list of page names and descriptions to render them as shortcuts in the sidebar. Uses Jinja2 templating. ```html {# vim: set et ts=8 sts=4 sw=4 ai ft=jinja.html: #} {% extends "settings.html" %} {% block content %} ... {% for name, description in [ ("home", ' Home'), ("pageindex", ' A - Z'), ("changelog", ' Changelog'), ("createpage", ' Create Page'), ] %} {{description|safe}} {% endfor %} ... {% endblock %} ``` -------------------------------- ### Wiki Core Routes Source: https://context7.com/redimp/otterwiki/llms.txt Routes for core wiki functionalities like index, changelog, search, and help. ```APIDOC ## GET / - Home Page ### Description Displays the home page of the wiki. ### Method GET ### Endpoint / ``` ```APIDOC ## GET / ### Description View a page or attachment. ### Method GET ### Endpoint / ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page or attachment. ``` ```APIDOC ## GET /-/index ### Description Displays an index of all pages (A-Z listing). ### Method GET ### Endpoint /-/index ``` ```APIDOC ## GET /-/changelog ### Description Displays a list of recent changes in the wiki. ### Method GET ### Endpoint /-/changelog ``` ```APIDOC ## GET /-/search ### Description Provides search functionality for wiki pages. ### Method GET ### Endpoint /-/search ``` ```APIDOC ## GET /-/create ### Description Displays the form to create a new page. ### Method GET ### Endpoint /-/create ``` ```APIDOC ## GET /-/about ### Description Displays information about the OtterWiki instance. ### Method GET ### Endpoint /-/about ``` ```APIDOC ## GET /-/help ### Description Displays user help documentation. ### Method GET ### Endpoint /-/help ``` ```APIDOC ## GET /-/syntax ### Description Displays documentation on the markdown syntax used. ### Method GET ### Endpoint /-/syntax ``` -------------------------------- ### Manage Git Remote UI and Webhook Generation Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/admin/repository_management.html Initializes event listeners for Git configuration toggles and handles the dynamic generation of secure webhook URLs using the Web Crypto API. ```javascript document.addEventListener('DOMContentLoaded', function() { const pushCheckbox = document.getElementById('git_remote_push_enabled'); const pushParams = document.getElementById('git_remote_push_params'); function togglePushFields() { if (pushCheckbox.checked) { pushParams.style.display = 'block'; } else { pushParams.style.display = 'none'; } } togglePushFields(); pushCheckbox.addEventListener('change', togglePushFields); const pullCheckbox = document.getElementById('git_remote_pull_enabled'); const pullParams = document.getElementById('git_remote_pull_params'); const pullUrlInput = document.getElementById('git_remote_pull_url'); const webhookUrlInput = document.getElementById('git_remote_pull_webhook_url'); const copyButton = document.getElementById('copy_webhook_url'); async function generateWebhookHash(url) { if (!url) return ''; // generate SHA-256 hash to match backend expectation const str = url + 'otterwiki'; const encoder = new TextEncoder(); const data = encoder.encode(str); const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); return hashHex; } async function updateWebhookUrl() { const remoteUrl = pullUrlInput.value.trim(); if (remoteUrl) { const hash = await generateWebhookHash(remoteUrl); const webhookUrl = window.location.origin + '/-/api/v1/pull/' + hash; webhookUrlInput.value = webhookUrl; } else { webhookUrlInput.value = ''; } } function togglePullFields() { if (pullCheckbox.checked) { pullParams.style.display = 'block'; updateWebhookUrl(); } else { pullParams.style.display = 'none'; } } togglePullFields(); pullCheckbox.addEventListener('change', togglePullFields); pullUrlInput.addEventListener('input', updateWebhookUrl); copyButton.addEventListener('click', function() { webhookUrlInput.select(); webhookUrlInput.setSelectionRange(0, 99999); // For mobile devices navigator.clipboard.writeText(webhookUrlInput.value).then(function() { const originalText = copyButton.innerHTML; copyButton.innerHTML = ''; setTimeout(function() { copyButton.innerHTML = originalText; }, 2000); }).catch(function() { // fallback for older browsers document.execCommand('copy'); const originalText = copyButton.innerHTML; copyButton.innerHTML = ''; setTimeout(function() { copyButton.innerHTML = originalText; }, 2000); }); }); {% if git_action_result %} // scroll to results area after a short delay setTimeout(function() { const resultsElement = document.getElementById('git_action_results'); if (resultsElement) { resultsElement.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }, 100); {% endif %} }); ``` -------------------------------- ### Access Application via Port-Forward for ClusterIP Service Source: https://github.com/redimp/otterwiki/blob/main/helm/templates/NOTES.txt These commands are used to access the application when the service type is ClusterIP. It retrieves the Pod name and container port, then sets up a port-forward to localhost. ```bash export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "otterwiki.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT ``` -------------------------------- ### Page Index Mode Options Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/admin/sidebar_preferences.html Renders options for the Page Index display mode using Jinja2 templating. Includes modes for not displayed, sorted, grouped directories, and directories only. ```html Page Index Mode {% for mode in [("", "Not displayed"),("SORTED","Directories and pages, sorted"),("DIRECTORIES_GROUPED","Directories and pages, with directories grouped first"),("DIRECTORIES_ONLY","Directories only")] %} {{mode[1]}} {% endfor %} ``` -------------------------------- ### Configure CodeMirror Editor Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/editor.html Initializes and configures the CodeMirror editor for markdown. Sets up various options like mode, line numbers, themes, and key bindings for enhanced editing experience. ```javascript const cm_editor = CodeMirror.fromTextArea(document.getElementById("content_editor"), { mode: 'markdown', lineNumbers: true, theme: "otterwiki", lineWrapping: true, indentWithTabs: false, spellcheck: true, inputStyle: 'contenteditable', indentUnit: 4, autofocus: true, fencedCodeBlockHighlighting: true, fencedCodeBlockDefaultMode: "bash", extraKeys: { "Enter": "newlineAndIndentContinueMarkdownList", 'Cmd-S': function () { return false }, 'Ctrl-S': function () { return false }, "Shift-Tab": "indentLess", // Better Tab "Tab": (cm) => { if (cm.somethingSelected()) { cm.execCommand('indentMore'); } else { cm.execCommand('insertSoftTab'); } } }, }); cm_editor.setCursor({ line: {{cursor_line or 0}}, ch: {{cursor_ch or 0}} } ); const bottom_panel = document.getElementById('editor-bottom-panel'); bottom_panel.style.display = 'block'; cm_editor.addPanel(bottom_panel, {position: "bottom", stable: true}); ``` -------------------------------- ### Reference Flask URL Routes Source: https://context7.com/redimp/otterwiki/llms.txt A list of available URL patterns for page management, wiki navigation, authentication, and administration. ```python # Page routes GET / # Home page GET / # View page or attachment GET //view # View page GET //view/ # View page at revision GET //edit # Edit page POST //save # Save page GET //history # Page history GET //diff// # Compare revisions GET //blame # Line-by-line attribution GET //rename # Rename page form GET //delete # Delete page form GET //source # View markdown source GET //attachments # List attachments GET //a/ # Get attachment GET //t/ # Get thumbnail # Wiki routes GET /-/index # Page index (A-Z listing) GET /-/changelog # Recent changes GET /-/search # Search pages GET /-/create # Create new page GET /-/about # About page GET /-/help # User help GET /-/syntax # Markdown syntax help # Authentication routes GET /-/login # Login form GET /-/logout # Logout GET /-/register # Registration form GET /-/settings # User settings GET /-/lost_password # Password recovery # Admin routes (require admin permission) GET /-/admin # Admin panel GET /-/admin/user_management # User management GET /-/admin/sidebar_preferences # Sidebar config GET /-/admin/permissions_and_registration # Access settings GET /-/admin/mail_preferences # Mail configuration GET /-/admin/repository_management # Git settings ``` -------------------------------- ### Page Index Focus Options Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/admin/sidebar_preferences.html Displays options for the Page Index focus, allowing users to choose between focusing on the current subtree or always displaying all pages. ```html Page Index Focus SUBTREE OFF {% for mode in [("SUBTREE", "Focus on current subtree"),("OFF","Always display all pages")] %} {{mode[1]}} {% endfor %} ``` -------------------------------- ### CLI User Management Source: https://context7.com/redimp/otterwiki/llms.txt Flask CLI commands for managing users, including listing, creating, editing, and deleting users, as well as password management. ```APIDOC ## CLI User Management ```bash # List all users flask user list flask user list --json # Create a new user flask user create user@example.com "John Doe" flask user create admin@example.com "Admin User" -p admin flask user create user@example.com "Jane" --flags=email_confirmed,approved --permissions=read,write # Edit user flask user edit user@example.com --new-name="Jane Doe" flask user edit user@example.com --new-email=newemail@example.com flask user edit user@example.com --flags=email_confirmed,approved flask user edit user@example.com --permissions=read,write,upload # Password management flask user password user@example.com --interactive # Prompt for password flask user password user@example.com --generate # Generate random password flask user password user@example.com --send-password-reset # Send reset email flask user password user@example.com --delete # Remove password (disable login) # Delete user flask user delete user@example.com flask user delete user@example.com --confirm # Skip confirmation prompt ``` ``` -------------------------------- ### Render Markdown and Syntax Highlighting Source: https://context7.com/redimp/otterwiki/llms.txt Utilize OtterwikiRenderer for extended markdown processing and pygments_render for syntax-highlighted code blocks. ```python from otterwiki.renderer import OtterwikiRenderer, pygments_render # Initialize renderer with configuration renderer = OtterwikiRenderer(config={ 'RENDERER_HTML_ALLOWLIST': 'iframe[src width height]', # Custom allowed HTML }) # Render markdown to HTML with table of contents markdown_text = """ # Welcome This is **bold** and *italic* text. ## Features - Tables with sorting - Code highlighting - Mermaid diagrams - MathJax equations ```python def hello(): print("Hello, World!") ``` ```mermaid graph LR A[Start] --> B[Process] B --> C[End] ``` Math: $E = mc^2$ | Column 1 | Column 2 | |----------|----------| | Data 1 | Data 2 | """ html, toc, library_requirements = renderer.markdown(markdown_text) # toc structure: [(index, html_text, level, raw_text, anchor_id), ...] for idx, text, level, raw, anchor in toc: print(f"{' ' * (level-1)}- [{raw}](#{anchor})") # library_requirements indicates needed JS libraries # {'requires_mermaid': True, 'requires_mathjax': True, 'requires_datatables': True} # Render code with syntax highlighting code = ''' def fibonacci(n): if n <= 1: return n return fibonacci(n-1) + fibonacci(n-2) ''' highlighted = pygments_render(code, lang='python', linenumbers=True) ``` -------------------------------- ### Initialize Sortable Custom Menu Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/admin/sidebar_preferences.html JavaScript code to initialize Sortable.js for the custom menu, enabling drag-and-drop reordering of menu items. ```javascript Sortable.create(document.getElementById('custom-page-index'), { sort: true, handle: '.btn-handle', animation: 150, }); ``` -------------------------------- ### Defining Abbreviations Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Syntax for defining abbreviations that show tooltips on hover. ```markdown *[HTML]: Hyper Text Markup Language *[W3C]: World Wide Web Consortium ``` -------------------------------- ### MathJax Integration Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Syntax for inline and block-level mathematical equations. ```markdown Inline math: `$a^2+b^2=c^2$` ``` ```markdown ```math a^2+b^2=c^2 ``` ``` ```markdown Inline Math: $a^2+b^2=c^2$ ``` ```markdown Equation: $$a^2+b^2=c^2$$ ``` -------------------------------- ### Git HTTP Server Source: https://context7.com/redimp/otterwiki/llms.txt Information about the Git HTTP server endpoint for cloning and pushing. ```APIDOC ## Git Operations ### Description Allows direct interaction with the wiki's Git repository via HTTP. ### Method GET (for cloning), POST (for pushing) ### Endpoint http://localhost:8080/.git ### Usage 1. Clone the repository: ```bash git clone http://localhost:8080/.git wiki-content ``` 2. Make changes within the `wiki-content` directory. 3. Push changes: ```bash cd wiki-content git push origin main ``` ### Notes This feature is available when `GIT_WEB_SERVER` is set to `True`. ``` -------------------------------- ### Code Blocks and Syntax Highlighting Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Syntax for inline code, fenced code blocks, and enabling line numbers. ```markdown Inline code `int n = 1` with backticks. ``` ```markdown ``` Code Blocks ``` ``` ```markdown ```python #!/usr/bin/env python assert 1 + 1 == 2 print("Hello World!") ``` ``` ```markdown ```python= print("Hello Line Numbers!") ``` ``` -------------------------------- ### Manage Users via Python API Source: https://context7.com/redimp/otterwiki/llms.txt Interact with the authentication module to manage user accounts, permissions, and session information. ```python from otterwiki.auth import ( get_author, has_permission, current_user, get_all_user, get_user, create_user, update_user, delete_user ) # Get current user info for commits author = get_author() # Returns: ('User Name', 'email@example.com') # Check permissions (READ, WRITE, UPLOAD, ADMIN) if has_permission('WRITE'): # User can edit pages pass if has_permission('ADMIN'): # User has admin privileges pass # Access current user object if current_user.is_authenticated: print(f"Logged in as: {current_user.name}") print(f"Email: {current_user.email}") print(f"Is admin: {current_user.is_admin}") print(f"Is approved: {current_user.is_approved}") # Admin: List all users users = get_all_user() for user in users: print(f"{user.email}: admin={user.is_admin}, approved={user.is_approved}") # Admin: Get specific user user = get_user(email='user@example.com') user = get_user(uid=123) # Admin: Update user permissions user.is_approved = True user.allow_read = True user.allow_write = True update_user(user) ``` -------------------------------- ### Iterate Through User List Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/admin/user_management.html Used to loop through a list of users for display or processing. ```html {% for user in user_list %} {% endfor %} ``` -------------------------------- ### Defining Footnotes Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Syntax for creating and referencing footnotes. ```markdown Footnote identifiers[^1] are single characters or words[^bignote]. And can be referenced multiple[^1] times. [^1]: Footnotes can be a single line. [^bignote]: Or more complex. Indent paragraphs to include them in the footnote. Add as many paragraphs as you like. ``` -------------------------------- ### Preview Toggle Functionality Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/editor.html Handles the 'onclick' event for the preview button, switching the view to preview mode. It sends the current content to the server for rendering and updates the UI with the preview and table of contents. ```javascript preview_btn.onclick = function() { /* toggle preview/edit */ preview_block.style.display = 'block'; for (const editor_block of editor_blocks) { editor_block.style.display = 'none'; } editor_btn.style.display = ''; preview_btn.style.display = 'none'; extranav_attachments.style.display = 'none'; content_wrapper.classList.add("preview-background"); const formData = new FormData(); formData.append("content", cm_editor.getValue()); formData.append("cursor_line", cm_editor.getCursor().line); formData.append("cursor_ch", cm_editor.getCursor().ch); /* FIXME: display loader */ fetch({{ url_for('preview', path=pagepath) | tojson }}, { method: 'POST', headers: {'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').content}, body: formData, }) .then(function (response) { return response.json(); }) .then(function (data) { preview_block.innerHTML = data.preview_content; sidebar_toc.innerHTML = data.preview_toc; extranav_toc.innerHTML = data.preview_toc; if (data.preview_js) { try { eval(data.preview_js); } catch(e) { console.log("Error", e.stack); console.log("Error", e.name); console.log("Error", e.message); } } }) .then(function () { cursor = document.getElementById("otterwiki_cursor"); // update MathJax if loaded if (typeof MathJax !== 'undefined') { MathJax.typeset(); } // update Mermaid if loaded if (typeof mermaid !== 'undefined') { otterwiki.update_mermaid(); } if (cursor) { cursor.scrollIntoView({ behavior: 'instant', block: 'center', inline: 'nearest' }); } }) .catch(function () { console.log('Error fetching preview ...'); }); } ``` -------------------------------- ### Custom Menu Configuration Loop Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/admin/sidebar_preferences.html Jinja2 loop for rendering custom menu entries. It includes fields for link, title, and icon, with an empty entry added for user input. ```html {% for entry in custom_menu + [{"link":"","title":"","icon":""}] %} {% endfor %} ``` -------------------------------- ### Authentication Routes Source: https://context7.com/redimp/otterwiki/llms.txt Routes related to user authentication and settings. ```APIDOC ## GET /-/login ### Description Displays the login form. ### Method GET ### Endpoint /-/login ``` ```APIDOC ## GET /-/logout ### Description Logs the current user out. ### Method GET ### Endpoint /-/logout ``` ```APIDOC ## GET /-/register ### Description Displays the user registration form. ### Method GET ### Endpoint /-/register ``` ```APIDOC ## GET /-/settings ### Description Displays the user settings page. ### Method GET ### Endpoint /-/settings ``` ```APIDOC ## GET /-/lost_password ### Description Displays the password recovery form. ### Method GET ### Endpoint /-/lost_password ``` -------------------------------- ### Admin Routes Source: https://context7.com/redimp/otterwiki/llms.txt Routes for administrative tasks, requiring admin permissions. ```APIDOC ## GET /-/admin ### Description Displays the main administration panel. ### Method GET ### Endpoint /-/admin ``` ```APIDOC ## GET /-/admin/user_management ### Description Provides tools for managing users. ### Method GET ### Endpoint /-/admin/user_management ``` ```APIDOC ## GET /-/admin/sidebar_preferences ### Description Allows configuration of sidebar preferences. ### Method GET ### Endpoint /-/admin/sidebar_preferences ``` ```APIDOC ## GET /-/admin/permissions_and_registration ### Description Manages access settings and registration options. ### Method GET ### Endpoint /-/admin/permissions_and_registration ``` ```APIDOC ## GET /-/admin/mail_preferences ### Description Allows configuration of email settings. ### Method GET ### Endpoint /-/admin/mail_preferences ``` ```APIDOC ## GET /-/admin/repository_management ### Description Provides settings for managing the Git repository. ### Method GET ### Endpoint /-/admin/repository_management ``` -------------------------------- ### General API Endpoints Source: https://context7.com/redimp/otterwiki/llms.txt These are general utility endpoints for OtterWiki. ```APIDOC ## GET /-/healthz ### Description Health check endpoint. ### Method GET ### Endpoint /-/healthz ### Response #### Success Response (200) - "OK" (string) - Indicates the service is healthy. #### Error Response (503) - Service Unavailable ``` ```APIDOC ## GET /-/changelog/feed.rss ### Description Provides the changelog as an RSS feed. ### Method GET ### Endpoint /-/changelog/feed.rss ``` ```APIDOC ## GET /-/changelog/feed.atom ### Description Provides the changelog as an Atom feed. ### Method GET ### Endpoint /-/changelog/feed.atom ``` ```APIDOC ## GET /-/sitemap.xml ### Description Generates a sitemap for search engines. ### Method GET ### Endpoint /-/sitemap.xml ``` -------------------------------- ### Conditional Link to Add User Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/admin/user_management.html Conditionally renders a link to add a user if editing features are supported. Ensure 'auth_supported_features' is defined and 'editing' key exists. ```html {% if auth_supported_features['editing'] %} [Add User]({{ url_for_}}){% endif %} ``` -------------------------------- ### Implement an OtterWiki Plugin Source: https://context7.com/redimp/otterwiki/llms.txt Defines a plugin class using the @hookimpl decorator to interface with various lifecycle events and rendering hooks. ```python from otterwiki.plugins import hookimpl class MyPlugin: @hookimpl def setup(self, app, db, storage): """Called once during app initialization.""" self.app = app self.storage = storage app.logger.info("MyPlugin initialized") @hookimpl def renderer_markdown_preprocess(self, md: str) -> str: """Transform markdown before rendering.""" # Example: Convert custom syntax return md.replace('::note::', '
') @hookimpl def renderer_html_postprocess(self, html: str) -> str: """Transform HTML after markdown rendering.""" return html.replace('', '
') @hookimpl def page_saved(self, pagepath, content, author, message): """Called after a page is saved.""" print(f"Page {pagepath} saved by {author[0]}") @hookimpl def page_deleted(self, pagepath, author, message): """Called after a page is deleted.""" pass @hookimpl def repository_changed(self, changed_files: list): """Called when repository changes (edit, pull, push).""" for f in changed_files: print(f"Changed: {f}") @hookimpl def template_html_head_inject(self, page) -> str: """Inject HTML into section.""" return '' @hookimpl def template_html_body_inject(self, page) -> str: """Inject HTML before .""" return '' @hookimpl def info(self) -> tuple: """Return plugin info: (name, description, category).""" return ("My Plugin", "Adds custom features", "General") @hookimpl def help(self, plugin: str) -> tuple: """Return plugin help: (title, markdown_content).""" if plugin == "myplugin": return ("My Plugin Help", "## Usage\n\nDocumentation here...") return None ``` -------------------------------- ### GitStorage File Operations Source: https://context7.com/redimp/otterwiki/llms.txt Methods for storing, loading, and managing files within the version-controlled repository. ```APIDOC ## GitStorage Operations ### Description Provides methods to interact with the git-backed storage system for file management and version control. ### Methods - **store(filename, content, message, author)**: Saves a file with a commit message and author details. - **load(filename, revision=None)**: Retrieves file content, optionally at a specific revision. - **metadata(filename)**: Returns metadata including revision, datetime, author, and commit message. - **list(path=None, depth=None)**: Lists files and directories in the repository. - **rename(old_name, new_name, message, author)**: Renames a file in the repository. - **delete(filenames, message, author)**: Deletes one or more files. - **log(filename=None)**: Retrieves the commit history for the repository or a specific file. - **diff(rev_a, rev_b)**: Returns the difference between two revisions. - **revert(revision, message, author)**: Reverts a specific commit. - **blame(filename)**: Returns line-by-line authorship information for a file. ``` -------------------------------- ### Formatting Text with Markdown Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Basic text formatting including bold, italics, strikethrough, and marking text. ```markdown **bold** _italics_ strikethrough mark ``` ```markdown \*literal asterisks\* ``` -------------------------------- ### Embedding Images Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/snippets/syntax.html Syntax for embedding images via URL. ```markdown ![](http://www.example.com/image.jpg) ``` -------------------------------- ### GitStorage API for Version-Controlled Operations Source: https://context7.com/redimp/otterwiki/llms.txt The GitStorage class provides version-controlled file operations using a git repository. It supports storing, loading, listing, renaming, deleting, reverting, and diffing files, as well as retrieving commit logs and blame information. ```python from otterwiki.gitstorage import GitStorage, StorageNotFound, StorageError # Initialize storage with a git repository path storage = GitStorage('/path/to/repository') # Store a file with version control storage.store( filename='pages/my-page.md', content='# My Page\n\nContent here.', message='Created my page', author=('John Doe', 'john@example.com') ) # Load file content (optionally at a specific revision) content = storage.load('pages/my-page.md') content_old = storage.load('pages/my-page.md', revision='abc123') # Get file metadata (author, datetime, revision) metadata = storage.metadata('pages/my-page.md') # Returns: {'revision': 'abc123', 'datetime': datetime, # 'author_name': 'John', 'author_email': 'john@example.com', # 'message': 'commit message'} # List files and directories files, directories = storage.list() files, dirs = storage.list('subdirectory/', depth=1) # Get commit log for a file or entire repository log = storage.log() # All commits log = storage.log('pages/my-page.md') # File history # Rename a file storage.rename('old-name.md', 'new-name.md', message='Renamed file', author=('John', 'john@example.com')) # Delete files storage.delete(['pages/old-page.md'], message='Deleted old page', author=('John', 'john@example.com')) # Get diff between revisions diff = storage.diff('rev_a', 'rev_b') # Revert a commit storage.revert('abc123', message='Revert bad change', author=('John', 'john@example.com')) # Get blame information for a file blame_data = storage.blame('pages/my-page.md') # Returns list of: (revision, author, datetime, line_num, line_content, message) ``` -------------------------------- ### Display User Name Source: https://github.com/redimp/otterwiki/blob/main/otterwiki/templates/admin/user_management.html Displays the name of a user object. Assumes 'user' object has a 'name' attribute. ```html {{user.name}} ``` -------------------------------- ### Page Management Routes Source: https://context7.com/redimp/otterwiki/llms.txt Routes for viewing, editing, saving, and managing individual pages. ```APIDOC ## GET //view ### Description View a specific page. ### Method GET ### Endpoint //view ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page to view. ``` ```APIDOC ## GET //view/ ### Description View a specific revision of a page. ### Method GET ### Endpoint //view/ ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page. - **revision** (string) - Required - The revision identifier. ``` ```APIDOC ## GET //edit ### Description Open the edit form for a page. ### Method GET ### Endpoint //edit ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page to edit. ``` ```APIDOC ## POST //save ### Description Save changes to a page. ### Method POST ### Endpoint //save ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page to save. #### Request Body - **content** (string) - Required - The new content of the page. - **author** (string) - Optional - The author of the change. - **message** (string) - Optional - The commit message. ``` ```APIDOC ## GET //history ### Description View the revision history of a page. ### Method GET ### Endpoint //history ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page. ``` ```APIDOC ## GET //diff// ### Description Compare two revisions of a page. ### Method GET ### Endpoint //diff// ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page. - **rev_a** (string) - Required - The first revision identifier. - **rev_b** (string) - Required - The second revision identifier. ``` ```APIDOC ## GET //blame ### Description Show line-by-line attribution for a page. ### Method GET ### Endpoint //blame ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page. ``` ```APIDOC ## GET //rename ### Description Open the rename form for a page. ### Method GET ### Endpoint //rename ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page to rename. ``` ```APIDOC ## GET //delete ### Description Open the delete form for a page. ### Method GET ### Endpoint //delete ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page to delete. ``` ```APIDOC ## GET //source ### Description View the markdown source of a page. ### Method GET ### Endpoint //source ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page. ``` ```APIDOC ## GET //attachments ### Description List attachments for a page. ### Method GET ### Endpoint //attachments ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page. ``` ```APIDOC ## GET //a/ ### Description Get a specific attachment for a page. ### Method GET ### Endpoint //a/ ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page. - **filename** (string) - Required - The name of the attachment. ``` ```APIDOC ## GET //t/ ### Description Get a thumbnail for an attachment of a page. ### Method GET ### Endpoint //t/ ### Parameters #### Path Parameters - **path** (string) - Required - The path of the page. - **filename** (string) - Required - The name of the attachment. ```