cashmere

cashmere

org-backend

Code

;;; org-backend.el -*- lexical-binding: t; -*-
;;; org-backend.el --- Minimal backend for editing and serving Org files via HTTP
(require 'web-server)
(require 'ox)
(require 'ox-html)
(require 'ox-latex)
(require 'ox-ascii)

(defcustom org-backend-docroot "/home/cashmere/org"
  "Document root for editable Org files."
  :type 'string
  :group 'org-backend)

;; Variable sofort initialisieren, nicht nur deklarieren
(defvar org-ehtml-dir-match "^\\([^\.].*[^~]\\|\\.\\.\\)$"
  "Match string passed to `directory-files-and-attributes' for dir listing.")

;; Debug-Variable für besseres Error-Tracking
(defvar org-backend-debug t
  "Enable debug output for org-backend.")

(defvar org-backend-handler
  '(((:GET  . ".*") . org-backend-file-handler)
    ((:POST . ".*") . org-backend-edit-handler)))

;; Hilfsfunktion für besseres Logging
(defun org-backend-log (message &rest args)
  "Log MESSAGE with ARGS when debugging is enabled."
  (when org-backend-debug
    (apply #'message (concat "[ORG-BACKEND] " message) args)))

;; Inline JavaScript für Editor
(defun org-backend-get-editor-js ()
  "Return the editor JavaScript code as a string."
  "
$(document).ready(function() { initializeEditor(); });
let originalOrgContent = null;
let orgFilePath = null;

function initializeEditor() {
    if ($('#org-editor-controls').length === 0) {
        $('body').prepend(`
            <div id=\"org-editor-controls\" style=\"
                position: fixed;
                top: 10px;
                right: 10px;
                z-index: 9999;
                background: #f0f0f0;
                padding: 10px;
                border: 1px solid #ccc;
                border-radius: 5px;
                box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            \">
                <button id=\"edit-page-btn\" class=\"btn-edit\">📝 Edit Page</button>
                <span id=\"edit-status\" style=\"margin-left: 10px; color: #666;\"></span>
            </div>
            <div id=\"org-editor-modal\" style=\"
                display: none;
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0,0,0,0.8);
                z-index: 10000;
            \">
                <div style=\"
                    position: absolute;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    background: white;
                    width: 90%;
                    height: 90%;
                    padding: 20px;
                    border-radius: 10px;
                    display: flex;
                    flex-direction: column;
                \">
                    <h2 style=\"margin-top: 0;\">Edit Org File</h2>
                    <textarea id=\"org-content-editor\" style=\"
                        flex: 1;
                        width: 100%;
                        font-family: 'Courier New', monospace;
                        font-size: 14px;
                        border: 1px solid #ccc;
                        padding: 10px;
                        resize: none;
                    \"></textarea>
                    <div style=\"margin-top: 10px;\">
                        <button id=\"save-org-btn\" style=\"
                            background: #4CAF50;
                            color: white;
                            padding: 10px 20px;
                            border: none;
                            border-radius: 5px;
                            cursor: pointer;
                            margin-right: 10px;
                        \">💾 Save</button>
                        <button id=\"cancel-edit-btn\" style=\"
                            background: #f44336;
                            color: white;
                            padding: 10px 20px;
                            border: none;
                            border-radius: 5px;
                            cursor: pointer;
                            margin-right: 10px;
                        \">❌ Cancel</button>
                        <button id=\"preview-btn\" style=\"
                            background: #2196F3;
                            color: white;
                            padding: 10px 20px;
                            border: none;
                            border-radius: 5px;
                            cursor: pointer;
                        \">👁️ Preview</button>
                        <span id=\"save-status\" style=\"margin-left: 20px;\"></span>
                    </div>
                </div>
            </div>
        `);

        $('#edit-page-btn').click(loadOrgContent);
        $('#save-org-btn').click(saveOrgContent);
        $('#cancel-edit-btn').click(closeEditor);
        $('#preview-btn').click(previewChanges);

        $(document).keyup(function(e) {
            if (e.key === \"Escape\") {
                closeEditor();
            }
        });
    }
}

function loadOrgContent() {
    let currentPath = window.location.pathname;

    if (currentPath.endsWith('.html')) {
        orgFilePath = currentPath.replace('.html', '.org');
    } else if (currentPath === '/' || currentPath === '') {
        orgFilePath = '/index.org';
    } else {
        orgFilePath = currentPath + '.org';
    }

    $('#edit-status').text('Loading...');

    $.ajax({
        type: 'GET',
        url: orgFilePath,
        dataType: 'text',
        success: function(content) {
            originalOrgContent = content;
            $('#org-content-editor').val(content);
            $('#org-editor-modal').show();
            $('#edit-status').text('');
        },
        error: function(xhr) {
            $('#edit-status').text('Error loading file');
            alert('Could not load Org file: ' + xhr.statusText);
        }
    });
}

function saveOrgContent() {
    const newContent = $('#org-content-editor').val();

    if (newContent === originalOrgContent) {
        $('#save-status').text('No changes to save');
        setTimeout(() => $('#save-status').text(''), 2000);
        return;
    }

    $('#save-status').text('Saving...');

    $.ajax({
        type: 'POST',
        url: window.location.pathname,
        data: {
            org: newContent,
            beg: 0,
            end: originalOrgContent.length,
            path: orgFilePath,
            reexport: 'html'  // Signal zum Re-Export
        },
        success: function() {
            $('#save-status').text('✅ Saved! Reloading...');
            originalOrgContent = newContent;
            setTimeout(() => {
                window.location.reload();
            }, 1000);
        },
        error: function(xhr) {
            $('#save-status').text('❌ Error: ' + xhr.responseText);
        }
    });
}

function closeEditor() {
    if ($('#org-content-editor').val() !== originalOrgContent) {
        if (!confirm('You have unsaved changes. Are you sure you want to close?')) {
            return;
        }
    }
    $('#org-editor-modal').hide();
    $('#org-content-editor').val('');
    originalOrgContent = null;
}

function previewChanges() {
    const newContent = $('#org-content-editor').val();

    if (newContent === originalOrgContent) {
        alert('No changes to preview');
        return;
    }

    $('#save-status').text('Generating preview...');

    if (confirm('This will save your changes and reload the page. Continue?')) {
        saveOrgContent();
    }
}
")

(defun org-backend-file-handler (request)
  "Handle GET requests to serve exported Org files."
  (condition-case err
      (with-slots (process headers) request
        (let* ((url-path (substring (cdr (assoc :GET headers)) 1))
               (path (ws-in-directory-p org-backend-docroot url-path)))

          ;; Debug-Ausgabe
          (org-backend-log "GET Request: URL=%s, Resolved Path=%s" url-path path)

          ;; Spezialbehandlung für edit-org.js
          (when (string= url-path "edit-org.js")
            (let ((js-file (expand-file-name "edit-org.js" org-backend-docroot)))
              (if (file-exists-p js-file)
                  (progn
                    (org-backend-log "Serving edit-org.js from file")
                    (ws-send-file process js-file))
                ;; Sende inline JavaScript wenn Datei nicht existiert
                (progn
                  (org-backend-log "Serving edit-org.js inline")
                  (ws-response-header process 200 '("Content-type" . "application/javascript"))
                  (process-send-string process (org-backend-get-editor-js))))
              (throw 'handled t)))

          (cond
           ;; If file is not in doc root return 404 not found
           ((not path)
            (org-backend-log "Path not in docroot: %s" url-path)
            (ws-send-404 process))

           ;; List directory
           ((file-directory-p path)
            (org-backend-log "Listing directory: %s" path)
            (org-backend-send-directory-list process path))

           ;; Check if this is a request for an exported format
           ((and path
                 (member (file-name-extension path) '("html" "tex" "txt")))
            (let* ((base-path (file-name-sans-extension path))
                   (org-file (concat base-path ".org")))
              (org-backend-log "Export request: %s -> %s" org-file path)
              (if (file-exists-p org-file)
                  (org-backend-export-and-send process org-file url-path)
                (ws-send-404 process))))

           ;; Serve .org files directly
           ((and (file-exists-p path)
                 (string= (file-name-extension path) "org"))
            (org-backend-log "Serving org file: %s" path)
            (ws-send-file process path))

           ;; Serve other existing files
           ((file-exists-p path)
            (org-backend-log "Serving file: %s" path)
            (ws-send-file process path))

           ;; File not found
           (t
            (org-backend-log "File not found: %s" path)
            (ws-send-404 process)))))
    (handled nil) ; Früher Ausstieg wenn bereits behandelt
    (error
     (let ((error-msg (format "Error in file-handler:\nPath: %s\nError: %s\nBacktrace: %s"
                              (cdr (assoc :GET headers))
                              (error-message-string err)
                              (with-output-to-string (backtrace)))))
       (org-backend-log "ERROR: %s" error-msg)
       (ws-response-header process 500 '("Content-type" . "text/html"))
       (process-send-string 
        process 
        (concat "<html><body><h1>500 Internal Server Error</h1>"
                "<pre>" (xml-escape-string error-msg) "</pre>"
                "</body></html>"))))))

(defun org-backend-send-directory-list (process path)
  "Send HTML directory listing with export options for Org files."
  (condition-case err
      (progn
        ;; Sicherstellen, dass path mit / endet
        (unless (string-suffix-p "/" path)
          (setq path (concat path "/")))

        (ws-response-header process 200 '("Content-type" . "text/html"))
        (process-send-string 
         process
         (concat "<html><head><title>Directory Listing</title>"
                   "<link rel='stylesheet' href='https://cashmere.rs/static/latex.css'>"
                 "<style>"
                 "body { font-family: monospace; margin: 20px; }"
                 "ul { list-style-type: none; }"
                 "li { margin: 5px 0; }"
                 ".export-options { margin-left: 20px; color: #666; }"
                 "</style>"
                 "</head><body>"
                 "<h2>Directory: " (xml-escape-string path) "</h2>"
                 "<ul>"
                 (mapconcat
                  (lambda (f)
                    (unless (string-match-p "^\\." f) ; Skip hidden files
                      (let* ((full (expand-file-name f path))
                             (is-dir (file-directory-p full))
                             (ext (if is-dir "/" ""))
                             (url (url-encode-url (concat f ext))))
                        (format "<li><a href=\"%s\">%s%s</a></li>" url f ext))))
                  (directory-files path nil nil t)
                  "\n")
                 "</ul>"
                 (let ((org-files (directory-files path nil "\\.org$")))
                   (when org-files
                     (concat "<h3>Export Options for Org Files:</h3><ul>"
                             (mapconcat
                              (lambda (f)
                                (let ((base (file-name-sans-extension f)))
                                  (concat 
                                   (format "<li>%s.org → " base)
                                   "<span class='export-options'>"
                                   (mapconcat
                                    (lambda (ext)
                                      (format "<a href=\"%s.%s\">%s</a>" 
                                              base ext ext))
                                    '("html" "tex" "txt") " | ")
                                   "</span></li>")))
                              org-files
                              "\n")
                             "</ul>")))
                 "</body></html>")))
    (error
     (let ((error-msg (format "Error in directory listing:\nPath: %s\nError: %s"
                              path (error-message-string err))))
       (org-backend-log "ERROR: %s" error-msg)
       (ws-response-header process 500 '("Content-type" . "text/html"))
       (process-send-string 
        process 
        (concat "<html><body><h1>Directory Listing Error</h1>"
                "<pre>" (xml-escape-string error-msg) "</pre>"
                "</body></html>"))))))

;; Erweiterte Export-Funktion mit JavaScript-Injection
(defun org-backend-export-file-with-editor (org-file type)
  "Export ORG-FILE to TYPE with editor functionality."
  (let* ((base (file-name-sans-extension org-file))
         (ext-name (cond ((eq type 'html) "html")
                         ((eq type 'latex) "tex")
                         ((eq type 'ascii) "txt")))
         (export-file (concat base "." ext-name)))
    (save-window-excursion
      (with-current-buffer (find-file-noselect org-file)
        (pcase type
          ('html 
           ;; Export zu HTML mit custom Header
           (let ((org-html-head-extra
                  (concat 
                   "<script src='https://code.jquery.com/jquery-3.6.0.min.js'></script>\n"
                   "<script src='/edit-org.js'></script>\n"
                   "<link rel='stylesheet' href='https://cashmere.rs/static/latex.css'>"
                   "<style>\n"
                   "#org-editor-controls button {\n"
                   "  font-size: 14px;\n"
                   "  padding: 5px 10px;\n"
                   "  cursor: pointer;\n"
                   "  border: none;\n"
                   "  background: #007bff;\n"
                   "  color: white;\n"
                   "  border-radius: 3px;\n"
                   "}\n"
                   "#org-editor-controls button:hover {\n"
                   "  background: #0056b3;\n"
                   "}\n"
                   "</style>\n")))
             (org-export-to-file 'html export-file)))
          ('latex (org-export-to-file 'latex export-file))
          ('ascii (org-export-to-file 'ascii export-file)))))
    export-file))

(defun org-backend-export-and-send (process org-file url-path)
  "Export Org file to requested format and send it."
  (let* ((ext (file-name-extension url-path))
         (type (cond ((string= ext "html") 'html)
                     ((string= ext "tex") 'latex)
                     ((string= ext "txt") 'ascii)
                     (t nil))))
    (org-backend-log "Exporting %s to %s" org-file ext)
    (cond
     ;; ASCII/TXT files - send org file directly  
     ((eq type 'ascii)
      (ws-send-file process org-file))
     ;; HTML mit Editor-Funktionalität
     ((eq type 'html)
      (condition-case err
          (let ((exported-file (org-backend-export-file-with-editor org-file type)))
            (if (file-exists-p exported-file)
                (progn
                  (org-backend-log "Export successful: %s" exported-file)
                  (ws-send-file process exported-file))
              (progn
                (org-backend-log "Export file not found: %s" exported-file)
                (ws-send-404 process))))
        (error
         (let ((error-msg (format "Export error:\nFile: %s\nType: %s\nError: %s"
                                  org-file type (error-message-string err))))
           (org-backend-log "ERROR: %s" error-msg)
           (ws-response-header process 500 '("Content-type" . "text/html"))
           (process-send-string 
            process 
            (concat "<html><body><h1>Export Error</h1>"
                    "<pre>" (xml-escape-string error-msg) "</pre>"
                    "</body></html>"))))))
     ;; Andere Export-Typen
     (type
      (condition-case err
          (let ((exported-file (org-backend-export-file org-file type)))
            (if (file-exists-p exported-file)
                (progn
                  (org-backend-log "Export successful: %s" exported-file)
                  (ws-send-file process exported-file))
              (progn
                (org-backend-log "Export file not found: %s" exported-file)
                (ws-send-404 process))))
        (error
         (let ((error-msg (format "Export error:\nFile: %s\nType: %s\nError: %s"
                                  org-file type (error-message-string err))))
           (org-backend-log "ERROR: %s" error-msg)
           (ws-response-header process 500 '("Content-type" . "text/plain"))
           (process-send-string process error-msg)))))
     ;; Unknown type
     (t
      (org-backend-log "Unknown export type: %s" ext)
      (ws-send-404 process)))))

(defun org-backend-export-file (org-file type)
  "Export ORG-FILE to TYPE and return the exported file path."
  (let* ((base (file-name-sans-extension org-file))
         (ext-name (cond ((eq type 'html) "html")
                         ((eq type 'latex) "tex")
                         ((eq type 'ascii) "txt")))
         (export-file (concat base "." ext-name)))
    (save-window-excursion
      (with-current-buffer (find-file-noselect org-file)
        (pcase type
          ('html (org-export-to-file 'html export-file))
          ('latex (org-export-to-file 'latex export-file))
          ('ascii (org-export-to-file 'ascii export-file)))))
    export-file))

(defun org-backend-edit-handler (request)
  "Handle POST requests to edit and save Org files."
  (condition-case err
      (with-slots (process headers) request
        (let* ((path (cdr (assoc "path" headers)))
               (beg  (string-to-number (or (cdr (assoc "beg" headers)) "0")))
               (end  (string-to-number (or (cdr (assoc "end" headers)) "0")))
               (text (decode-coding-string (or (cdr (assoc "org" headers)) "") 'utf-8-unix t))
               (reexport (cdr (assoc "reexport" headers))))
          (org-backend-log "Edit request: %s [%d-%d] reexport=%s" path beg end reexport)

          ;; Entferne führenden Slash wenn vorhanden
          (when (string-prefix-p "/" path)
            (setq path (substring path 1)))

          (let ((file-path (expand-file-name path org-backend-docroot)))
            (unless (ws-in-directory-p org-backend-docroot file-path)
              (error "Path outside docroot: %s" path))

            ;; Erstelle Datei wenn sie nicht existiert
            (unless (file-exists-p file-path)
              (make-directory (file-name-directory file-path) t))

            ;; Speichere die Änderungen
            (with-current-buffer (find-file-noselect file-path)
              (if (and (= beg 0) (= end 0))
                  ;; Vollständiger Datei-Replace
                  (progn
                    (erase-buffer)
                    (insert text))
                ;; Teilweiser Replace
                (let ((valid-beg (max (point-min) (min beg (point-max))))
                      (valid-end (max (point-min) (min end (point-max)))))
                  (goto-char valid-beg)
                  (delete-region valid-beg valid-end)
                  (insert text)))
              (save-buffer))

            ;; Re-Export nach HTML wenn gewünscht
            (when (and reexport (string= reexport "html"))
              (org-backend-log "Re-exporting %s to HTML" file-path)
              (condition-case export-err
                  (let ((html-file (org-backend-export-file-with-editor file-path 'html)))
                    (org-backend-log "Re-export successful: %s" html-file))
                (error
                 (org-backend-log "Re-export failed: %s" (error-message-string export-err))
                 ;; Wir lassen den Edit trotzdem erfolgreich sein
                 nil))))

          (ws-response-header process 200 '("Content-type" . "text/plain"))
          (process-send-string process "OK")))
    (error
     (let ((error-msg (format "Edit error:\nPath: %s\nError: %s"
                              (cdr (assoc "path" headers))
                              (error-message-string err))))
       (org-backend-log "ERROR: %s" error-msg)
       (ws-response-header process 500 '("Content-type" . "text/plain"))
       (process-send-string process error-msg)))))

;; Hilfsfunktion für XML-Escaping
(defun xml-escape-string (str)
  "Escape special characters in STR for HTML/XML."
  (when str
    (replace-regexp-in-string 
     "&" "&amp;"
     (replace-regexp-in-string 
      "<" "&lt;"
      (replace-regexp-in-string 
       ">" "&gt;"
       (replace-regexp-in-string 
        "\"" "&quot;"
        str))))))

(defun org-backend-start-server (port)
  "Start the minimal Org backend server on PORT."
  (org-backend-log "Starting server on port %d" port)
  (org-backend-log "Document root: %s" org-backend-docroot)
  (unless (file-directory-p org-backend-docroot)
    (error "Document root does not exist: %s" org-backend-docroot))
  (ws-start org-backend-handler port nil :host "localhost"))

(provide 'org-backend)
;;; org-backend.el ends here
;;; org-backend.el ends here

Notes

when i try to access http://localhost:8080 i get this error:

HTTP/1.1 500 Internal Server Error Content-type: text/plain

Caught Error: (void-variable org-ehtml-dir-match)

the auto conversion of the file does also not work. for example i try to access http://localhost:8080/inbox.html in theory it should convert my to html and then serve it. but i get 404 Not Found even though the inbox.org does exist.

cashmere@fedora:~/org$ ls inbox.org 
 inbox.org
cashmere@fedora:~/org$ 

404 Not Found

The edit function does work though.

Python Implementation

requests

import requests

headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Sec-GPC': '1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html', headers=headers)
curl 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html' \
  -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8' \
  -H 'Accept-Language: en-US,en;q=0.8' \
  -H 'Cache-Control: max-age=0' \
  -H 'Connection: keep-alive' \
  -H 'Referer: http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html' \
  -H 'Sec-Fetch-Dest: document' \
  -H 'Sec-Fetch-Mode: navigate' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'Sec-Fetch-User: ?1' \
  -H 'Sec-GPC: 1' \
  -H 'Upgrade-Insecure-Requests: 1' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "Linux"' ;
curl 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html' \
  -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8' \
  -H 'Accept-Language: en-US,en;q=0.8' \
  -H 'Connection: keep-alive' \
  -H 'Referer: http://localhost:8080/' \
  -H 'Sec-Fetch-Dest: document' \
  -H 'Sec-Fetch-Mode: navigate' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'Sec-Fetch-User: ?1' \
  -H 'Sec-GPC: 1' \
  -H 'Upgrade-Insecure-Requests: 1' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "Linux"' ;
curl 'https://code.jquery.com/jquery-3.6.0.min.js' \
  -H 'sec-ch-ua-platform: "Linux"' \
  -H 'Referer: http://localhost:8080/' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' ;
curl 'http://localhost:8080/edit-org.js' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en-US,en;q=0.8' \
  -H 'Connection: keep-alive' \
  -H 'Referer: http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html' \
  -H 'Sec-Fetch-Dest: script' \
  -H 'Sec-Fetch-Mode: no-cors' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'Sec-GPC: 1' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "Linux"' ;
curl 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.org' \
  -H 'Accept: text/plain, */*; q=0.01' \
  -H 'Accept-Language: en-US,en;q=0.8' \
  -H 'Connection: keep-alive' \
  -H 'Referer: http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'Sec-GPC: 1' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "Linux"' ;
curl 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en-US,en;q=0.8' \
  -H 'Connection: keep-alive' \
  -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
  -H 'Origin: http://localhost:8080' \
  -H 'Referer: http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'Sec-GPC: 1' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "Linux"' \
  --data-raw $'org=%23%2Btitle%3A++++++rabatzz%0A%23%2Bdate%3A+++++++%5B2025-07-24+Thu+21%3A52%5D%0A%23%2Bfiletags%3A+++%3Aprogramming%3Aproject%3Apython%3A%0A%23%2Bidentifier%3A+20250724T215259%0A%0A*+Current+state%0AFrontend+in+Progress%0A*+Tasks%0A**+Connect+Frontend+with+Backend%0A****+Tables%0A*****+Bookings%0A-+slot_id%0A-+customer_id%0A-+persons_count%0A-+booking_time%0A-+status%0A-+notes%0A*****+Customer%0A-+name%0A-+email%0A-+phone%0A*****+Timeslots%0A-+id%0A-+timeslot%0A-+capacity%0A*+xh%0A**+Dashboard+Login%0A%23%2Bbegin_src+bash%0Acurl+\'http%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Flogin\'+%5C%0A++-X+POST+%5C%0A++-H+\'User-Agent%3A+Mozilla%2F5.0+(X11%3B+Linux+x86_64%3B+rv%3A141.0)+Gecko%2F20100101+Firefox%2F141.0\'+%5C%0A++-H+\'Accept%3A+text%2Fhtml%2Capplication%2Fxhtml%2Bxml%2Capplication%2Fxml%3Bq%3D0.9%2C*%2F*%3Bq%3D0.8\'+%5C%0A++-H+\'Accept-Language%3A+en-US%2Cen%3Bq%3D0.5\'+%5C%0A++-H+\'Accept-Encoding%3A+gzip%2C+deflate%2C+br%2C+zstd\'+%5C%0A++-H+\'Content-Type%3A+application%2Fx-www-form-urlencoded\'+%5C%0A++-H+\'Origin%3A+http%3A%2F%2Flocalhost%3A8000\'+%5C%0A++-H+\'Sec-GPC%3A+1\'+%5C%0A++-H+\'Connection%3A+keep-alive\'+%5C%0A++-H+\'Referer%3A+http%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Flogin\'+%5C%0A++-H+\'Cookie%3A+session_token%3DSOl6G70eGHtdtxw-PKmV6NVQ59Vd5HFu-DrbIXc1lws%3B+session%3DeyJ0aW1lc2xvdHMubGFzdF92aWV3ZWQiOnsiIHQiOlsxLG51bGxdfX0.aI6HtA.pPKTYd7IH-0CWRatmZyqMHyhpwQ\'+%5C%0A++-H+\'Upgrade-Insecure-Requests%3A+1\'+%5C%0A++-H+\'Sec-Fetch-Dest%3A+document\'+%5C%0A++-H+\'Sec-Fetch-Mode%3A+navigate\'+%5C%0A++-H+\'Sec-Fetch-Site%3A+same-origin\'+%5C%0A++-H+\'Sec-Fetch-User%3A+%3F1\'+%5C%0A++-H+\'Priority%3A+u%3D0%2C+i\'+%5C%0A++-H+\'Pragma%3A+no-cache\'+%5C%0A++-H+\'Cache-Control%3A+no-cache\'+%5C%0A++--data-raw+\'username%3Dcashmere%5E%26password%3DRabatzz123%2521\'%0A%23%2Bend_src%0A**+Bookings%0A%23%2Bbegin_src+bash%0Axh+post+http%3A%2F%2Flocalhost%3A8000%2Fbookings+--form+vorname%3D%22max%22+nachname%3D%22mustermann%22+email%3D%22max.mustermann%40gmx.de%22+date%3D%22Freitag%2C+08.+August+2025%22+slot%3D%2211%3A00+-+15%3A00%22+toddler%3D1+child%3D1+adult%3D1%0A%23%2Bend_src%0A%0A**+Timeslots%0A%23%2Bbegin_src+bash%0Axh+post+http%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Ftimeslot%0A%23%2Bend_src%0A*+Tasks%0A**+TODO+%5B%23A%5D+Umbuchungen+(Backend)%0A**+%5B%23A%5D+Automatisch+Buchung+loeschen+nach+1+Stunde+wenn+kein+Check-In%0A**+%5B%23A%5D+Nach+Buchung-ID+suchen+koennen%0A**+%5B%23A%5D+Buchungen+bearbeiten+koennen%0A**+%5B%23A%5D+Kapazitaeten+manuell+anpassen+koennen%0A***+Einige+Tage+zb+nicht+reservieren%0A**+%5B%23A%5D+PDF+Export+mit+gewuenschten+Spalten%0A**+TODO+%5B%23A%5D+Timestamp+wann+Kunde+QR-Code+gescannt+hat%0A**+TODO+%5B%23A%5D+Jahreskalender+mit+unterschiedlichen+Oeffnungszeiten+fuer+maximale+Kapazitaet%0A**+TODO+%5B%23A%5D+Wallet+Funktion+(Google+Kalender%2C+Apple+etc.)%0A**+%5B%23A%5D+Unterschiedliche+Preise%0A***+Ab+19+Uhr+Happy-Hour+(guenstiger)%0A**+%5B%23B%5D+Kapazitaeten+im+Dashboard%0A**+Hetzner+fuer+Hosting%0A**+%5B%23C%5D+Bemerkungen+als+Art+Chat+darstellen%0A**++%5B%23C%5D+%5B%5Bhttps%3A%2F%2Fgithub.com%2Fcage-kiosk%2Fcage%5D%5BGitHub+-+cage-kiosk%2Fcage%3A+A+Wayland+kiosk%5D%5D%0A**+%5B%23C%5D+Preise+bearbeiten+koennen%0A**+%5B%23C%5D+Reservierungsgebuehren+verlangen%0A**+%5B%23C%5D+Uebernachtungen+mit+reinnehmen%0A-+Soll+nur+Anfrage+sein.%0A**+%5B%23C%5D+Gutscheinsystem%0A**+%5B%23C%5D+In+Zukunft+Onlinezahlungen%0A**+%5B%23C%5D+Uebernachtung+Anfrage%0A*+Dashboard%0A**+Jinja+Template+%26+HTMX%0A**+Meeting+rabatzz\u0021+%2B+Sevde%0ASCHEDULED%3A+%3C2025-08-09+Sat+14%3A00-16%3A00%3E%0A**+Buchungen%0A**+Export%0A**+WAIT+QR-Code+Scanner%0A-+State+%22WAIT%22+++++++from++++++++++++++%5B2025-08-08+Fri+15%3A21%5D+%5C%5C%0A++muss+abgeholt+werden%0A**+Sevde+macht+Frontend+fuer+Dashboard%0A**+TODO+Ab+morgen+direkt+anfangen%0A*+Notizen+von+Rabatzz%0A*+Nutzung+von+Jinja+Templates%0AUm+die+Komplexitaet+simpel+zu+halten%2C+kommt+der+Einsatz+von+Jinja+Templates.%0A**+Basis+definieren%0AUm+das+Grundgeruest+eines+Jinja+Templates+zu+bilden%2C+muss+erstmal+muss+erstmal+das+Template+von+der+%3Dbase.html%3D+%22ummantelt%22+werden.%0Adies+erreichen+wir+wie+folgt%3A%0A%23%2Bbegin_src+html%0A%7B%25+extends+%22base.html%22+%25%7D%0A%23%2Bend_src%0A**+Deklarierung+des+Templates%0AJetzt+koennen+wir+das+eigentliche+Template+deklarieren%3A%0A%23%2Bbegin_src+html%0A%7B+block+content+%7D%0A%0A%7B+endblock+content+%7D%0A%23%2Bend_src%0AZwischen+block+und+endlock+kann+nun+der+HTML+Code+eingefuegt+werden.%0A%0A**+Resultat%0AUm+die+Uebersicht+zu+behalten%2C+kann+man+gerne+ueber+der+HTML+Datei+noch+in+einem+Kommentar+eintragen%2C+zu+welcher+python+datei+das+Template+zugewiesen+ist.%0A%23%2Bbegin_src+html%0A%3C\u0021--+src%2Frouter%2Fdashboard%2Fbookings.py+--%3E%0A%7B%25+extends+%22base.html%22+%25%7D%0A%7B+block+content+%7D%0A%0A%7B+endblock+content+%7D%0A%23%2Bend_src%0A**+Variablen+in+den+Templates+anzeigen+lassen%0AUm+Variablen+anzeigen+zu+lassen+muss+man+doppelte+geschweifte+Klammern+nutzen+und+zwar+so%3A+%3D%7B%7B%7D%7D%3D%0A%0AUm+richtig+auf+die+Werte+der+Variable+zuzugreifen%2C+m%C3%BCssen+wir+wissen+wie+die+Variable+booking+strukturiert+ist%3A%0A%23%2Bbegin_src+python%0Aclass+Booking%3A%0A++++id%3A+int%0A++++adult%3A+int%0A++++child%3A+int%0A++++toddler%3A+int%0A++++vorname%3A+str%0A++++nachname%3A+str%0A++++email%3A+str%0A++++timeslot_id%3A+int%0A++++date%3A+str%0A++++booking_data%3A+str%0A%23%2Bend_src%0A%0AAls+n%C3%A4chstes+k%C3%B6nnen+wir+dann+ganz+einfach+im+Template+Beispielsweise+in+%3Dvalue%3D+und+%3Dplaceholder%3D+%3D%7B%7Bbooking.email%7D%7D%3D+eintragen%3A%0A%23%2Bbegin_src+html%0A%3Cdiv+class%3D%22form-control%22%3E%0A++++++++++%3Clabel+class%3D%22label%22%3E%0A++++++++++++%3Cspan+class%3D%22label-text+font-medium%22%3EE-Mail%3C%2Fspan%3E%0A++++++++++%3C%2Flabel%3E%0A++++++++++%3Cinput%0A++++++++++++type%3D%22email%22%0A++++++++++++name%3D%22email%22%0A++++++++++++class%3D%22input+input-bordered+w-full%22%0A++++++++++++value%3D%22%7B%7Bbooking.email%7D%7D%22%0A++++++++++++placeholder%3D%22%7B%7Bbooking.email%7D%7D%22%0A++++++++++++required%0A++++++++++%2F%3E%0A++++++++%3C%2Fdiv%3E%0A%23%2Bend_src%0A%0AGeht+man+nun+%5B%5Bhttp%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Fbookings%2Fedit%2F10%5D%5Bhier%5D%5D+hin%2C+so+wird+automatisch+die+eingetragen.%0A*+%5B%5Bhttps%3A%2F%2Fdrive.google.com%2Fdrive%2Fu%2F0%2Ffolders%2F1tgbpKBg9HE5o7vKpN5anZgRB2ETCQXJ4%5D%5Brabatzz_reservierungssystem+%E2%80%93+Google%C2%A0Drive%5D%5D%0A%0A%0A%0A&beg=0&end=5268&path=%2F20250724T215259--rabatzz__programming_project_python.org' ;
curl 'https://code.jquery.com/jquery-3.6.0.min.js' \
  -H 'sec-ch-ua-platform: "Linux"' \
  -H 'Referer: http://localhost:8080/' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' ;
curl 'http://localhost:8080/edit-org.js' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en-US,en;q=0.8' \
  -H 'Connection: keep-alive' \
  -H 'Referer: http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html' \
  -H 'Sec-Fetch-Dest: script' \
  -H 'Sec-Fetch-Mode: no-cors' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'Sec-GPC: 1' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "Linux"'
import requests

headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.8',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Sec-GPC': '1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html', headers=headers)


headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Sec-GPC': '1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html', headers=headers)


headers = {
    'sec-ch-ua-platform': '"Linux"',
    'Referer': 'http://localhost:8080/',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
}

response = requests.get('https://code.jquery.com/jquery-3.6.0.min.js', headers=headers)


headers = {
    'Accept': '*/*',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'script',
    'Sec-Fetch-Mode': 'no-cors',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-GPC': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/edit-org.js', headers=headers)


headers = {
    'Accept': 'text/plain, */*; q=0.01',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-GPC': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/20250724T215259--rabatzz__programming_project_python.org', headers=headers)


headers = {
    'Accept': '*/*',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'Origin': 'http://localhost:8080',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-GPC': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

data = "org=%23%2Btitle%3A++++++rabatzz%0A%23%2Bdate%3A+++++++%5B2025-07-24+Thu+21%3A52%5D%0A%23%2Bfiletags%3A+++%3Aprogramming%3Aproject%3Apython%3A%0A%23%2Bidentifier%3A+20250724T215259%0A%0A*+Current+state%0AFrontend+in+Progress%0A*+Tasks%0A**+Connect+Frontend+with+Backend%0A****+Tables%0A*****+Bookings%0A-+slot_id%0A-+customer_id%0A-+persons_count%0A-+booking_time%0A-+status%0A-+notes%0A*****+Customer%0A-+name%0A-+email%0A-+phone%0A*****+Timeslots%0A-+id%0A-+timeslot%0A-+capacity%0A*+xh%0A**+Dashboard+Login%0A%23%2Bbegin_src+bash%0Acurl+'http%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Flogin'+%5C%0A++-X+POST+%5C%0A++-H+'User-Agent%3A+Mozilla%2F5.0+(X11%3B+Linux+x86_64%3B+rv%3A141.0)+Gecko%2F20100101+Firefox%2F141.0'+%5C%0A++-H+'Accept%3A+text%2Fhtml%2Capplication%2Fxhtml%2Bxml%2Capplication%2Fxml%3Bq%3D0.9%2C*%2F*%3Bq%3D0.8'+%5C%0A++-H+'Accept-Language%3A+en-US%2Cen%3Bq%3D0.5'+%5C%0A++-H+'Accept-Encoding%3A+gzip%2C+deflate%2C+br%2C+zstd'+%5C%0A++-H+'Content-Type%3A+application%2Fx-www-form-urlencoded'+%5C%0A++-H+'Origin%3A+http%3A%2F%2Flocalhost%3A8000'+%5C%0A++-H+'Sec-GPC%3A+1'+%5C%0A++-H+'Connection%3A+keep-alive'+%5C%0A++-H+'Referer%3A+http%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Flogin'+%5C%0A++-H+'Cookie%3A+session_token%3DSOl6G70eGHtdtxw-PKmV6NVQ59Vd5HFu-DrbIXc1lws%3B+session%3DeyJ0aW1lc2xvdHMubGFzdF92aWV3ZWQiOnsiIHQiOlsxLG51bGxdfX0.aI6HtA.pPKTYd7IH-0CWRatmZyqMHyhpwQ'+%5C%0A++-H+'Upgrade-Insecure-Requests%3A+1'+%5C%0A++-H+'Sec-Fetch-Dest%3A+document'+%5C%0A++-H+'Sec-Fetch-Mode%3A+navigate'+%5C%0A++-H+'Sec-Fetch-Site%3A+same-origin'+%5C%0A++-H+'Sec-Fetch-User%3A+%3F1'+%5C%0A++-H+'Priority%3A+u%3D0%2C+i'+%5C%0A++-H+'Pragma%3A+no-cache'+%5C%0A++-H+'Cache-Control%3A+no-cache'+%5C%0A++--data-raw+'username%3Dcashmere%5E%26password%3DRabatzz123%2521'%0A%23%2Bend_src%0A**+Bookings%0A%23%2Bbegin_src+bash%0Axh+post+http%3A%2F%2Flocalhost%3A8000%2Fbookings+--form+vorname%3D%22max%22+nachname%3D%22mustermann%22+email%3D%22max.mustermann%40gmx.de%22+date%3D%22Freitag%2C+08.+August+2025%22+slot%3D%2211%3A00+-+15%3A00%22+toddler%3D1+child%3D1+adult%3D1%0A%23%2Bend_src%0A%0A**+Timeslots%0A%23%2Bbegin_src+bash%0Axh+post+http%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Ftimeslot%0A%23%2Bend_src%0A*+Tasks%0A**+TODO+%5B%23A%5D+Umbuchungen+(Backend)%0A**+%5B%23A%5D+Automatisch+Buchung+loeschen+nach+1+Stunde+wenn+kein+Check-In%0A**+%5B%23A%5D+Nach+Buchung-ID+suchen+koennen%0A**+%5B%23A%5D+Buchungen+bearbeiten+koennen%0A**+%5B%23A%5D+Kapazitaeten+manuell+anpassen+koennen%0A***+Einige+Tage+zb+nicht+reservieren%0A**+%5B%23A%5D+PDF+Export+mit+gewuenschten+Spalten%0A**+TODO+%5B%23A%5D+Timestamp+wann+Kunde+QR-Code+gescannt+hat%0A**+TODO+%5B%23A%5D+Jahreskalender+mit+unterschiedlichen+Oeffnungszeiten+fuer+maximale+Kapazitaet%0A**+TODO+%5B%23A%5D+Wallet+Funktion+(Google+Kalender%2C+Apple+etc.)%0A**+%5B%23A%5D+Unterschiedliche+Preise%0A***+Ab+19+Uhr+Happy-Hour+(guenstiger)%0A**+%5B%23B%5D+Kapazitaeten+im+Dashboard%0A**+Hetzner+fuer+Hosting%0A**+%5B%23C%5D+Bemerkungen+als+Art+Chat+darstellen%0A**++%5B%23C%5D+%5B%5Bhttps%3A%2F%2Fgithub.com%2Fcage-kiosk%2Fcage%5D%5BGitHub+-+cage-kiosk%2Fcage%3A+A+Wayland+kiosk%5D%5D%0A**+%5B%23C%5D+Preise+bearbeiten+koennen%0A**+%5B%23C%5D+Reservierungsgebuehren+verlangen%0A**+%5B%23C%5D+Uebernachtungen+mit+reinnehmen%0A-+Soll+nur+Anfrage+sein.%0A**+%5B%23C%5D+Gutscheinsystem%0A**+%5B%23C%5D+In+Zukunft+Onlinezahlungen%0A**+%5B%23C%5D+Uebernachtung+Anfrage%0A*+Dashboard%0A**+Jinja+Template+%26+HTMX%0A**+Meeting+rabatzz!+%2B+Sevde%0ASCHEDULED%3A+%3C2025-08-09+Sat+14%3A00-16%3A00%3E%0A**+Buchungen%0A**+Export%0A**+WAIT+QR-Code+Scanner%0A-+State+%22WAIT%22+++++++from++++++++++++++%5B2025-08-08+Fri+15%3A21%5D+%5C%5C%0A++muss+abgeholt+werden%0A**+Sevde+macht+Frontend+fuer+Dashboard%0A**+TODO+Ab+morgen+direkt+anfangen%0A*+Notizen+von+Rabatzz%0A*+Nutzung+von+Jinja+Templates%0AUm+die+Komplexitaet+simpel+zu+halten%2C+kommt+der+Einsatz+von+Jinja+Templates.%0A**+Basis+definieren%0AUm+das+Grundgeruest+eines+Jinja+Templates+zu+bilden%2C+muss+erstmal+muss+erstmal+das+Template+von+der+%3Dbase.html%3D+%22ummantelt%22+werden.%0Adies+erreichen+wir+wie+folgt%3A%0A%23%2Bbegin_src+html%0A%7B%25+extends+%22base.html%22+%25%7D%0A%23%2Bend_src%0A**+Deklarierung+des+Templates%0AJetzt+koennen+wir+das+eigentliche+Template+deklarieren%3A%0A%23%2Bbegin_src+html%0A%7B+block+content+%7D%0A%0A%7B+endblock+content+%7D%0A%23%2Bend_src%0AZwischen+block+und+endlock+kann+nun+der+HTML+Code+eingefuegt+werden.%0A%0A**+Resultat%0AUm+die+Uebersicht+zu+behalten%2C+kann+man+gerne+ueber+der+HTML+Datei+noch+in+einem+Kommentar+eintragen%2C+zu+welcher+python+datei+das+Template+zugewiesen+ist.%0A%23%2Bbegin_src+html%0A%3C!--+src%2Frouter%2Fdashboard%2Fbookings.py+--%3E%0A%7B%25+extends+%22base.html%22+%25%7D%0A%7B+block+content+%7D%0A%0A%7B+endblock+content+%7D%0A%23%2Bend_src%0A**+Variablen+in+den+Templates+anzeigen+lassen%0AUm+Variablen+anzeigen+zu+lassen+muss+man+doppelte+geschweifte+Klammern+nutzen+und+zwar+so%3A+%3D%7B%7B%7D%7D%3D%0A%0AUm+richtig+auf+die+Werte+der+Variable+zuzugreifen%2C+m%C3%BCssen+wir+wissen+wie+die+Variable+booking+strukturiert+ist%3A%0A%23%2Bbegin_src+python%0Aclass+Booking%3A%0A++++id%3A+int%0A++++adult%3A+int%0A++++child%3A+int%0A++++toddler%3A+int%0A++++vorname%3A+str%0A++++nachname%3A+str%0A++++email%3A+str%0A++++timeslot_id%3A+int%0A++++date%3A+str%0A++++booking_data%3A+str%0A%23%2Bend_src%0A%0AAls+n%C3%A4chstes+k%C3%B6nnen+wir+dann+ganz+einfach+im+Template+Beispielsweise+in+%3Dvalue%3D+und+%3Dplaceholder%3D+%3D%7B%7Bbooking.email%7D%7D%3D+eintragen%3A%0A%23%2Bbegin_src+html%0A%3Cdiv+class%3D%22form-control%22%3E%0A++++++++++%3Clabel+class%3D%22label%22%3E%0A++++++++++++%3Cspan+class%3D%22label-text+font-medium%22%3EE-Mail%3C%2Fspan%3E%0A++++++++++%3C%2Flabel%3E%0A++++++++++%3Cinput%0A++++++++++++type%3D%22email%22%0A++++++++++++name%3D%22email%22%0A++++++++++++class%3D%22input+input-bordered+w-full%22%0A++++++++++++value%3D%22%7B%7Bbooking.email%7D%7D%22%0A++++++++++++placeholder%3D%22%7B%7Bbooking.email%7D%7D%22%0A++++++++++++required%0A++++++++++%2F%3E%0A++++++++%3C%2Fdiv%3E%0A%23%2Bend_src%0A%0AGeht+man+nun+%5B%5Bhttp%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Fbookings%2Fedit%2F10%5D%5Bhier%5D%5D+hin%2C+so+wird+automatisch+die+eingetragen.%0A*+%5B%5Bhttps%3A%2F%2Fdrive.google.com%2Fdrive%2Fu%2F0%2Ffolders%2F1tgbpKBg9HE5o7vKpN5anZgRB2ETCQXJ4%5D%5Brabatzz_reservierungssystem+%E2%80%93+Google%C2%A0Drive%5D%5D%0A%0A%0A%0A&beg=0&end=5268&path=%2F20250724T215259--rabatzz__programming_project_python.org"

response = requests.post(
    'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    headers=headers,
    data=data,
)


headers = {
    'sec-ch-ua-platform': '"Linux"',
    'Referer': 'http://localhost:8080/',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
}

response = requests.get('https://code.jquery.com/jquery-3.6.0.min.js', headers=headers)


headers = {
    'Accept': '*/*',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'script',
    'Sec-Fetch-Mode': 'no-cors',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-GPC': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/edit-org.js', headers=headers)
import requests

headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.8',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Sec-GPC': '1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html', headers=headers)


headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1',
    'Sec-GPC': '1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html', headers=headers)


headers = {
    'sec-ch-ua-platform': '"Linux"',
    'Referer': 'http://localhost:8080/',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
}

response = requests.get('https://code.jquery.com/jquery-3.6.0.min.js', headers=headers)


headers = {
    'Accept': '*/*',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'script',
    'Sec-Fetch-Mode': 'no-cors',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-GPC': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/edit-org.js', headers=headers)


headers = {
    'Accept': 'text/plain, */*; q=0.01',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-GPC': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
e   'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/20250724T215259--rabatzz__programming_project_python.org', headers=headers)


headers = {
    'Accept': '*/*',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'Origin': 'http://localhost:8080',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-GPC': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

data = "org=%23%2Btitle%3A++++++rabatzz%0A%23%2Bdate%3A+++++++%5B2025-07-24+Thu+21%3A52%5D%0A%23%2Bfiletags%3A+++%3Aprogramming%3Aproject%3Apython%3A%0A%23%2Bidentifier%3A+20250724T215259%0A%0A*+Current+state%0AFrontend+in+Progress%0A*+Tasks%0A**+Connect+Frontend+with+Backend%0A****+Tables%0A*****+Bookings%0A-+slot_id%0A-+customer_id%0A-+persons_count%0A-+booking_time%0A-+status%0A-+notes%0A*****+Customer%0A-+name%0A-+email%0A-+phone%0A*****+Timeslots%0A-+id%0A-+timeslot%0A-+capacity%0A*+xh%0A**+Dashboard+Login%0A%23%2Bbegin_src+bash%0Acurl+'http%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Flogin'+%5C%0A++-X+POST+%5C%0A++-H+'User-Agent%3A+Mozilla%2F5.0+(X11%3B+Linux+x86_64%3B+rv%3A141.0)+Gecko%2F20100101+Firefox%2F141.0'+%5C%0A++-H+'Accept%3A+text%2Fhtml%2Capplication%2Fxhtml%2Bxml%2Capplication%2Fxml%3Bq%3D0.9%2C*%2F*%3Bq%3D0.8'+%5C%0A++-H+'Accept-Language%3A+en-US%2Cen%3Bq%3D0.5'+%5C%0A++-H+'Accept-Encoding%3A+gzip%2C+deflate%2C+br%2C+zstd'+%5C%0A++-H+'Content-Type%3A+application%2Fx-www-form-urlencoded'+%5C%0A++-H+'Origin%3A+http%3A%2F%2Flocalhost%3A8000'+%5C%0A++-H+'Sec-GPC%3A+1'+%5C%0A++-H+'Connection%3A+keep-alive'+%5C%0A++-H+'Referer%3A+http%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Flogin'+%5C%0A++-H+'Cookie%3A+session_token%3DSOl6G70eGHtdtxw-PKmV6NVQ59Vd5HFu-DrbIXc1lws%3B+session%3DeyJ0aW1lc2xvdHMubGFzdF92aWV3ZWQiOnsiIHQiOlsxLG51bGxdfX0.aI6HtA.pPKTYd7IH-0CWRatmZyqMHyhpwQ'+%5C%0A++-H+'Upgrade-Insecure-Requests%3A+1'+%5C%0A++-H+'Sec-Fetch-Dest%3A+document'+%5C%0A++-H+'Sec-Fetch-Mode%3A+navigate'+%5C%0A++-H+'Sec-Fetch-Site%3A+same-origin'+%5C%0A++-H+'Sec-Fetch-User%3A+%3F1'+%5C%0A++-H+'Priority%3A+u%3D0%2C+i'+%5C%0A++-H+'Pragma%3A+no-cache'+%5C%0A++-H+'Cache-Control%3A+no-cache'+%5C%0A++--data-raw+'username%3Dcashmere%5E%26password%3DRabatzz123%2521'%0A%23%2Bend_src%0A**+Bookings%0A%23%2Bbegin_src+bash%0Axh+post+http%3A%2F%2Flocalhost%3A8000%2Fbookings+--form+vorname%3D%22max%22+nachname%3D%22mustermann%22+email%3D%22max.mustermann%40gmx.de%22+date%3D%22Freitag%2C+08.+August+2025%22+slot%3D%2211%3A00+-+15%3A00%22+toddler%3D1+child%3D1+adult%3D1%0A%23%2Bend_src%0A%0A**+Timeslots%0A%23%2Bbegin_src+bash%0Axh+post+http%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Ftimeslot%0A%23%2Bend_src%0A*+Tasks%0A**+TODO+%5B%23A%5D+Umbuchungen+(Backend)%0A**+%5B%23A%5D+Automatisch+Buchung+loeschen+nach+1+Stunde+wenn+kein+Check-In%0A**+%5B%23A%5D+Nach+Buchung-ID+suchen+koennen%0A**+%5B%23A%5D+Buchungen+bearbeiten+koennen%0A**+%5B%23A%5D+Kapazitaeten+manuell+anpassen+koennen%0A***+Einige+Tage+zb+nicht+reservieren%0A**+%5B%23A%5D+PDF+Export+mit+gewuenschten+Spalten%0A**+TODO+%5B%23A%5D+Timestamp+wann+Kunde+QR-Code+gescannt+hat%0A**+TODO+%5B%23A%5D+Jahreskalender+mit+unterschiedlichen+Oeffnungszeiten+fuer+maximale+Kapazitaet%0A**+TODO+%5B%23A%5D+Wallet+Funktion+(Google+Kalender%2C+Apple+etc.)%0A**+%5B%23A%5D+Unterschiedliche+Preise%0A***+Ab+19+Uhr+Happy-Hour+(guenstiger)%0A**+%5B%23B%5D+Kapazitaeten+im+Dashboard%0A**+Hetzner+fuer+Hosting%0A**+%5B%23C%5D+Bemerkungen+als+Art+Chat+darstellen%0A**++%5B%23C%5D+%5B%5Bhttps%3A%2F%2Fgithub.com%2Fcage-kiosk%2Fcage%5D%5BGitHub+-+cage-kiosk%2Fcage%3A+A+Wayland+kiosk%5D%5D%0A**+%5B%23C%5D+Preise+bearbeiten+koennen%0A**+%5B%23C%5D+Reservierungsgebuehren+verlangen%0A**+%5B%23C%5D+Uebernachtungen+mit+reinnehmen%0A-+Soll+nur+Anfrage+sein.%0A**+%5B%23C%5D+Gutscheinsystem%0A**+%5B%23C%5D+In+Zukunft+Onlinezahlungen%0A**+%5B%23C%5D+Uebernachtung+Anfrage%0A*+Dashboard%0A**+Jinja+Template+%26+HTMX%0A**+Meeting+rabatzz!+%2B+Sevde%0ASCHEDULED%3A+%3C2025-08-09+Sat+14%3A00-16%3A00%3E%0A**+Buchungen%0A**+Export%0A**+WAIT+QR-Code+Scanner%0A-+State+%22WAIT%22+++++++from++++++++++++++%5B2025-08-08+Fri+15%3A21%5D+%5C%5C%0A++muss+abgeholt+werden%0A**+Sevde+macht+Frontend+fuer+Dashboard%0A**+TODO+Ab+morgen+direkt+anfangen%0A*+Notizen+von+Rabatzz%0A*+Nutzung+von+Jinja+Templates%0AUm+die+Komplexitaet+simpel+zu+halten%2C+kommt+der+Einsatz+von+Jinja+Templates.%0A**+Basis+definieren%0AUm+das+Grundgeruest+eines+Jinja+Templates+zu+bilden%2C+muss+erstmal+muss+erstmal+das+Template+von+der+%3Dbase.html%3D+%22ummantelt%22+werden.%0Adies+erreichen+wir+wie+folgt%3A%0A%23%2Bbegin_src+html%0A%7B%25+extends+%22base.html%22+%25%7D%0A%23%2Bend_src%0A**+Deklarierung+des+Templates%0AJetzt+koennen+wir+das+eigentliche+Template+deklarieren%3A%0A%23%2Bbegin_src+html%0A%7B+block+content+%7D%0A%0A%7B+endblock+content+%7D%0A%23%2Bend_src%0AZwischen+block+und+endlock+kann+nun+der+HTML+Code+eingefuegt+werden.%0A%0A**+Resultat%0AUm+die+Uebersicht+zu+behalten%2C+kann+man+gerne+ueber+der+HTML+Datei+noch+in+einem+Kommentar+eintragen%2C+zu+welcher+python+datei+das+Template+zugewiesen+ist.%0A%23%2Bbegin_src+html%0A%3C!--+src%2Frouter%2Fdashboard%2Fbookings.py+--%3E%0A%7B%25+extends+%22base.html%22+%25%7D%0A%7B+block+content+%7D%0A%0A%7B+endblock+content+%7D%0A%23%2Bend_src%0A**+Variablen+in+den+Templates+anzeigen+lassen%0AUm+Variablen+anzeigen+zu+lassen+muss+man+doppelte+geschweifte+Klammern+nutzen+und+zwar+so%3A+%3D%7B%7B%7D%7D%3D%0A%0AUm+richtig+auf+die+Werte+der+Variable+zuzugreifen%2C+m%C3%BCssen+wir+wissen+wie+die+Variable+booking+strukturiert+ist%3A%0A%23%2Bbegin_src+python%0Aclass+Booking%3A%0A++++id%3A+int%0A++++adult%3A+int%0A++++child%3A+int%0A++++toddler%3A+int%0A++++vorname%3A+str%0A++++nachname%3A+str%0A++++email%3A+str%0A++++timeslot_id%3A+int%0A++++date%3A+str%0A++++booking_data%3A+str%0A%23%2Bend_src%0A%0AAls+n%C3%A4chstes+k%C3%B6nnen+wir+dann+ganz+einfach+im+Template+Beispielsweise+in+%3Dvalue%3D+und+%3Dplaceholder%3D+%3D%7B%7Bbooking.email%7D%7D%3D+eintragen%3A%0A%23%2Bbegin_src+html%0A%3Cdiv+class%3D%22form-control%22%3E%0A++++++++++%3Clabel+class%3D%22label%22%3E%0A++++++++++++%3Cspan+class%3D%22label-text+font-medium%22%3EE-Mail%3C%2Fspan%3E%0A++++++++++%3C%2Flabel%3E%0A++++++++++%3Cinput%0A++++++++++++type%3D%22email%22%0A++++++++++++name%3D%22email%22%0A++++++++++++class%3D%22input+input-bordered+w-full%22%0A++++++++++++value%3D%22%7B%7Bbooking.email%7D%7D%22%0A++++++++++++placeholder%3D%22%7B%7Bbooking.email%7D%7D%22%0A++++++++++++required%0A++++++++++%2F%3E%0A++++++++%3C%2Fdiv%3E%0A%23%2Bend_src%0A%0AGeht+man+nun+%5B%5Bhttp%3A%2F%2Flocalhost%3A8000%2Fdashboard%2Fbookings%2Fedit%2F10%5D%5Bhier%5D%5D+hin%2C+so+wird+automatisch+die+eingetragen.%0A*+%5B%5Bhttps%3A%2F%2Fdrive.google.com%2Fdrive%2Fu%2F0%2Ffolders%2F1tgbpKBg9HE5o7vKpN5anZgRB2ETCQXJ4%5D%5Brabatzz_reservierungssystem+%E2%80%93+Google%C2%A0Drive%5D%5D%0A%0A%0A%0A&beg=0&end=5268&path=%2F20250724T215259--rabatzz__programming_project_python.org"

response = requests.post(
    'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    headers=headers,
    data=data,
)


headers = {
    'sec-ch-ua-platform': '"Linux"',
    'Referer': 'http://localhost:8080/',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
}

response = requests.get('https://code.jquery.com/jquery-3.6.0.min.js', headers=headers)


headers = {
    'Accept': '*/*',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive',
    'Referer': 'http://localhost:8080/20250724T215259--rabatzz__programming_project_python.html',
    'Sec-Fetch-Dest': 'script',
    'Sec-Fetch-Mode': 'no-cors',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-GPC': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Brave";v="140"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Linux"',
}

response = requests.get('http://localhost:8080/edit-org.js', headers=headers)