Strategy: TekDek foundational planning (personas, narrative, tools, Brick profile)
This commit is contained in:
7
skills/bookstack/.clawhub/origin.json
Normal file
7
skills/bookstack/.clawhub/origin.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "bookstack",
|
||||
"installedVersion": "1.0.3",
|
||||
"installedAt": 1775917021865
|
||||
}
|
||||
120
skills/bookstack/SKILL.md
Normal file
120
skills/bookstack/SKILL.md
Normal file
@@ -0,0 +1,120 @@
|
||||
---
|
||||
name: bookstack
|
||||
description: "BookStack Wiki & Documentation API integration. Manage your knowledge base programmatically: create, read, update, and delete books, chapters, pages, and shelves. Full-text search across all content. Use when you need to: (1) Create or edit wiki pages and documentation, (2) Organize content in books and chapters, (3) Search your knowledge base, (4) Automate documentation workflows, (5) Sync content between systems. Supports both HTML and Markdown content."
|
||||
metadata:
|
||||
openclaw:
|
||||
requires:
|
||||
env:
|
||||
- BOOKSTACK_URL
|
||||
- BOOKSTACK_TOKEN_ID
|
||||
- BOOKSTACK_TOKEN_SECRET
|
||||
---
|
||||
|
||||
# BookStack Skill
|
||||
|
||||
**BookStack** is an open-source wiki and documentation platform. This skill lets you manage your entire knowledge base via API – perfect for automation and integration.
|
||||
|
||||
## Features
|
||||
|
||||
- 📚 **Books** – create, edit, delete
|
||||
- 📑 **Chapters** – organize content within books
|
||||
- 📄 **Pages** – create/edit with HTML or Markdown
|
||||
- 🔍 **Full-text search** – search across all content
|
||||
- 📁 **Shelves** – organize books into collections
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# List all books
|
||||
python3 scripts/bookstack.py list_books
|
||||
|
||||
# Search the knowledge base
|
||||
python3 scripts/bookstack.py search "Home Assistant"
|
||||
|
||||
# Get a page
|
||||
python3 scripts/bookstack.py get_page 123
|
||||
|
||||
# Create a new page (Markdown)
|
||||
python3 scripts/bookstack.py create_page --book-id 1 --name "My Page" --markdown "# Title\n\nContent here..."
|
||||
```
|
||||
|
||||
## All Commands
|
||||
|
||||
### Books
|
||||
```bash
|
||||
python3 scripts/bookstack.py list_books # List all books
|
||||
python3 scripts/bookstack.py get_book <id> # Book details
|
||||
python3 scripts/bookstack.py create_book "Name" ["Desc"] # New book
|
||||
python3 scripts/bookstack.py update_book <id> [--name] [--description]
|
||||
python3 scripts/bookstack.py delete_book <id>
|
||||
```
|
||||
|
||||
### Chapters
|
||||
```bash
|
||||
python3 scripts/bookstack.py list_chapters # List all chapters
|
||||
python3 scripts/bookstack.py get_chapter <id> # Chapter details
|
||||
python3 scripts/bookstack.py create_chapter --book-id <id> --name "Name"
|
||||
python3 scripts/bookstack.py update_chapter <id> [--name] [--description]
|
||||
python3 scripts/bookstack.py delete_chapter <id>
|
||||
```
|
||||
|
||||
### Pages
|
||||
```bash
|
||||
python3 scripts/bookstack.py list_pages # List all pages
|
||||
python3 scripts/bookstack.py get_page <id> # Page preview
|
||||
python3 scripts/bookstack.py get_page <id> --content # With HTML content
|
||||
python3 scripts/bookstack.py get_page <id> --markdown # As Markdown
|
||||
|
||||
# Create page (in book or chapter)
|
||||
python3 scripts/bookstack.py create_page --book-id <id> --name "Name" --markdown "# Content"
|
||||
python3 scripts/bookstack.py create_page --chapter-id <id> --name "Name" --html "<p>HTML</p>"
|
||||
|
||||
# Edit page
|
||||
python3 scripts/bookstack.py update_page <id> [--name] [--content] [--markdown]
|
||||
python3 scripts/bookstack.py delete_page <id>
|
||||
```
|
||||
|
||||
### Search
|
||||
```bash
|
||||
python3 scripts/bookstack.py search "query" # Search everything
|
||||
python3 scripts/bookstack.py search "query" --type page # Pages only
|
||||
python3 scripts/bookstack.py search "query" --type book # Books only
|
||||
```
|
||||
|
||||
### Shelves
|
||||
```bash
|
||||
python3 scripts/bookstack.py list_shelves # List all shelves
|
||||
python3 scripts/bookstack.py get_shelf <id> # Shelf details
|
||||
python3 scripts/bookstack.py create_shelf "Name" ["Desc"] # New shelf
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Set the following environment variables:
|
||||
|
||||
```bash
|
||||
export BOOKSTACK_URL="https://your-bookstack.example.com"
|
||||
export BOOKSTACK_TOKEN_ID="your-token-id"
|
||||
export BOOKSTACK_TOKEN_SECRET="your-token-secret"
|
||||
```
|
||||
|
||||
Or configure via your gateway config file under `skills.entries.bookstack.env`.
|
||||
|
||||
### Create an API Token
|
||||
|
||||
1. Log in to your BookStack instance
|
||||
2. Go to **Edit Profile** → **API Tokens**
|
||||
3. Click **Create Token**
|
||||
4. Copy the Token ID and Secret
|
||||
|
||||
⚠️ The user needs a role with **"Access System API"** permission!
|
||||
|
||||
## API Reference
|
||||
|
||||
- **Base URL**: `{BOOKSTACK_URL}/api`
|
||||
- **Auth Header**: `Authorization: Token {ID}:{SECRET}`
|
||||
- **Official Docs**: https://demo.bookstackapp.com/api/docs
|
||||
|
||||
---
|
||||
|
||||
**Author**: xenofex7 | **Version**: 1.0.2
|
||||
6
skills/bookstack/_meta.json
Normal file
6
skills/bookstack/_meta.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn74cct4grf5r7mhc6rw5056e17z60s0",
|
||||
"slug": "bookstack",
|
||||
"version": "1.0.3",
|
||||
"publishedAt": 1770825967434
|
||||
}
|
||||
477
skills/bookstack/scripts/bookstack.py
Normal file
477
skills/bookstack/scripts/bookstack.py
Normal file
@@ -0,0 +1,477 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
BookStack API Integration
|
||||
Full CRUD for books, chapters, pages, shelves + search
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
|
||||
# Configuration from environment
|
||||
BASE_URL = os.getenv('BOOKSTACK_URL', '').rstrip('/')
|
||||
TOKEN_ID = os.getenv('BOOKSTACK_TOKEN_ID', '')
|
||||
TOKEN_SECRET = os.getenv('BOOKSTACK_TOKEN_SECRET', '')
|
||||
|
||||
def api_call(method, endpoint, data=None, params=None):
|
||||
"""Make API call to BookStack"""
|
||||
if not BASE_URL or not TOKEN_ID or not TOKEN_SECRET:
|
||||
print("❌ Error: BOOKSTACK_URL, BOOKSTACK_TOKEN_ID, and BOOKSTACK_TOKEN_SECRET required!")
|
||||
print(" Set them as environment variables or in your gateway config.")
|
||||
sys.exit(1)
|
||||
|
||||
url = f"{BASE_URL}/api/{endpoint}"
|
||||
|
||||
if params:
|
||||
url += '?' + urllib.parse.urlencode(params)
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
headers={
|
||||
"Authorization": f"Token {TOKEN_ID}:{TOKEN_SECRET}",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
},
|
||||
method=method
|
||||
)
|
||||
|
||||
if data:
|
||||
data = {k: v for k, v in data.items() if v is not None}
|
||||
req.data = json.dumps(data).encode()
|
||||
|
||||
with urllib.request.urlopen(req, timeout=30) as response:
|
||||
if response.status == 204:
|
||||
return None
|
||||
return json.loads(response.read().decode())
|
||||
|
||||
except urllib.error.HTTPError as e:
|
||||
try:
|
||||
error_data = json.loads(e.read().decode())
|
||||
print(f"❌ HTTP {e.code}: {error_data.get('error', {}).get('message', 'Unknown error')}")
|
||||
except:
|
||||
print(f"❌ HTTP {e.code}: {e.reason}")
|
||||
sys.exit(1)
|
||||
except urllib.error.URLError as e:
|
||||
print(f"❌ Connection error: {e.reason}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"❌ Error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# ============ BOOKS ============
|
||||
|
||||
def list_books(args):
|
||||
"""List all books"""
|
||||
params = {'count': args.count} if args.count else {}
|
||||
result = api_call("GET", "books", params=params)
|
||||
|
||||
if not result.get('data'):
|
||||
print("📚 No books found")
|
||||
return
|
||||
|
||||
print(f"📚 {result.get('total', len(result['data']))} Books:\n")
|
||||
for book in result['data']:
|
||||
desc = book.get('description', '')[:50] + '...' if book.get('description') else ''
|
||||
print(f" [{book['id']}] {book['name']}")
|
||||
if desc:
|
||||
print(f" {desc}")
|
||||
|
||||
def get_book(args):
|
||||
"""Get book details"""
|
||||
result = api_call("GET", f"books/{args.id}")
|
||||
print(f"📚 Book: {result['name']}")
|
||||
print(f" ID: {result['id']}")
|
||||
print(f" Slug: {result['slug']}")
|
||||
if result.get('description'):
|
||||
print(f" Description: {result['description']}")
|
||||
print(f" Created: {result['created_at']}")
|
||||
print(f" Updated: {result['updated_at']}")
|
||||
if result.get('contents'):
|
||||
print(f"\n Contents ({len(result['contents'])} items):")
|
||||
for item in result['contents'][:10]:
|
||||
icon = '📑' if item['type'] == 'chapter' else '📄'
|
||||
print(f" {icon} [{item['id']}] {item['name']}")
|
||||
|
||||
def create_book(args):
|
||||
"""Create a new book"""
|
||||
data = {
|
||||
"name": args.name,
|
||||
"description": args.description
|
||||
}
|
||||
result = api_call("POST", "books", data)
|
||||
print(f"✅ Book created: {result['name']} (ID: {result['id']})")
|
||||
|
||||
def update_book(args):
|
||||
"""Update a book"""
|
||||
data = {}
|
||||
if args.name:
|
||||
data['name'] = args.name
|
||||
if args.description:
|
||||
data['description'] = args.description
|
||||
|
||||
if not data:
|
||||
print("❌ Nothing to update. Use --name or --description")
|
||||
sys.exit(1)
|
||||
|
||||
result = api_call("PUT", f"books/{args.id}", data)
|
||||
print(f"✅ Book updated: {result['name']}")
|
||||
|
||||
def delete_book(args):
|
||||
"""Delete a book"""
|
||||
api_call("DELETE", f"books/{args.id}")
|
||||
print(f"✅ Book {args.id} deleted")
|
||||
|
||||
# ============ CHAPTERS ============
|
||||
|
||||
def list_chapters(args):
|
||||
"""List all chapters"""
|
||||
params = {'count': args.count} if args.count else {}
|
||||
result = api_call("GET", "chapters", params=params)
|
||||
|
||||
if not result.get('data'):
|
||||
print("📑 No chapters found")
|
||||
return
|
||||
|
||||
print(f"📑 {result.get('total', len(result['data']))} Chapters:\n")
|
||||
for ch in result['data']:
|
||||
print(f" [{ch['id']}] {ch['name']} (Book: {ch.get('book_id', '?')})")
|
||||
|
||||
def get_chapter(args):
|
||||
"""Get chapter details"""
|
||||
result = api_call("GET", f"chapters/{args.id}")
|
||||
print(f"📑 Chapter: {result['name']}")
|
||||
print(f" ID: {result['id']}")
|
||||
print(f" Book ID: {result['book_id']}")
|
||||
if result.get('description'):
|
||||
print(f" Description: {result['description']}")
|
||||
if result.get('pages'):
|
||||
print(f"\n Pages ({len(result['pages'])}):")
|
||||
for page in result['pages'][:10]:
|
||||
print(f" 📄 [{page['id']}] {page['name']}")
|
||||
|
||||
def create_chapter(args):
|
||||
"""Create a new chapter"""
|
||||
data = {
|
||||
"book_id": args.book_id,
|
||||
"name": args.name,
|
||||
"description": args.description
|
||||
}
|
||||
result = api_call("POST", "chapters", data)
|
||||
print(f"✅ Chapter created: {result['name']} (ID: {result['id']})")
|
||||
|
||||
def update_chapter(args):
|
||||
"""Update a chapter"""
|
||||
data = {}
|
||||
if args.name:
|
||||
data['name'] = args.name
|
||||
if args.description:
|
||||
data['description'] = args.description
|
||||
if args.book_id:
|
||||
data['book_id'] = args.book_id
|
||||
|
||||
if not data:
|
||||
print("❌ Nothing to update")
|
||||
sys.exit(1)
|
||||
|
||||
result = api_call("PUT", f"chapters/{args.id}", data)
|
||||
print(f"✅ Chapter updated: {result['name']}")
|
||||
|
||||
def delete_chapter(args):
|
||||
"""Delete a chapter"""
|
||||
api_call("DELETE", f"chapters/{args.id}")
|
||||
print(f"✅ Chapter {args.id} deleted")
|
||||
|
||||
# ============ PAGES ============
|
||||
|
||||
def list_pages(args):
|
||||
"""List all pages"""
|
||||
params = {'count': args.count} if args.count else {}
|
||||
result = api_call("GET", "pages", params=params)
|
||||
|
||||
if not result.get('data'):
|
||||
print("📄 No pages found")
|
||||
return
|
||||
|
||||
print(f"📄 {result.get('total', len(result['data']))} Pages:\n")
|
||||
for page in result['data']:
|
||||
location = f"Chapter {page['chapter_id']}" if page.get('chapter_id') else f"Book {page['book_id']}"
|
||||
print(f" [{page['id']}] {page['name']} ({location})")
|
||||
|
||||
def get_page(args):
|
||||
"""Get page with full content"""
|
||||
result = api_call("GET", f"pages/{args.id}")
|
||||
print(f"📄 Page: {result['name']}")
|
||||
print(f" ID: {result['id']}")
|
||||
print(f" Book ID: {result['book_id']}")
|
||||
if result.get('chapter_id'):
|
||||
print(f" Chapter ID: {result['chapter_id']}")
|
||||
print(f" Editor: {result.get('editor', 'unknown')}")
|
||||
print(f" Created: {result['created_at']}")
|
||||
print(f" Updated: {result['updated_at']}")
|
||||
|
||||
if args.content:
|
||||
print(f"\n--- Content (HTML) ---")
|
||||
print(result.get('html', ''))
|
||||
elif args.markdown:
|
||||
print(f"\n--- Content (Markdown) ---")
|
||||
print(result.get('markdown', result.get('html', '')))
|
||||
else:
|
||||
# Show preview
|
||||
html = result.get('html', '')
|
||||
if html:
|
||||
# Strip HTML tags for preview
|
||||
import re
|
||||
text = re.sub('<[^<]+?>', '', html)
|
||||
text = ' '.join(text.split())[:200]
|
||||
print(f"\n Preview: {text}...")
|
||||
|
||||
def create_page(args):
|
||||
"""Create a new page"""
|
||||
data = {
|
||||
"name": args.name,
|
||||
}
|
||||
|
||||
if args.book_id:
|
||||
data['book_id'] = args.book_id
|
||||
if args.chapter_id:
|
||||
data['chapter_id'] = args.chapter_id
|
||||
|
||||
if not args.book_id and not args.chapter_id:
|
||||
print("❌ Either --book-id or --chapter-id required")
|
||||
sys.exit(1)
|
||||
|
||||
if args.html:
|
||||
data['html'] = args.html
|
||||
elif args.markdown:
|
||||
data['markdown'] = args.markdown
|
||||
elif args.content:
|
||||
# Auto-detect: if starts with # or no HTML tags, treat as markdown
|
||||
if args.content.startswith('#') or '<' not in args.content:
|
||||
data['markdown'] = args.content
|
||||
else:
|
||||
data['html'] = args.content
|
||||
|
||||
result = api_call("POST", "pages", data)
|
||||
print(f"✅ Page created: {result['name']} (ID: {result['id']})")
|
||||
|
||||
def update_page(args):
|
||||
"""Update a page"""
|
||||
data = {}
|
||||
if args.name:
|
||||
data['name'] = args.name
|
||||
if args.html:
|
||||
data['html'] = args.html
|
||||
if args.markdown:
|
||||
data['markdown'] = args.markdown
|
||||
if args.content:
|
||||
if args.content.startswith('#') or '<' not in args.content:
|
||||
data['markdown'] = args.content
|
||||
else:
|
||||
data['html'] = args.content
|
||||
if args.book_id:
|
||||
data['book_id'] = args.book_id
|
||||
if args.chapter_id:
|
||||
data['chapter_id'] = args.chapter_id
|
||||
|
||||
if not data:
|
||||
print("❌ Nothing to update")
|
||||
sys.exit(1)
|
||||
|
||||
result = api_call("PUT", f"pages/{args.id}", data)
|
||||
print(f"✅ Page updated: {result['name']}")
|
||||
|
||||
def delete_page(args):
|
||||
"""Delete a page"""
|
||||
api_call("DELETE", f"pages/{args.id}")
|
||||
print(f"✅ Page {args.id} deleted")
|
||||
|
||||
# ============ SHELVES ============
|
||||
|
||||
def list_shelves(args):
|
||||
"""List all shelves"""
|
||||
params = {'count': args.count} if args.count else {}
|
||||
result = api_call("GET", "shelves", params=params)
|
||||
|
||||
if not result.get('data'):
|
||||
print("📁 No shelves found")
|
||||
return
|
||||
|
||||
print(f"📁 {result.get('total', len(result['data']))} Shelves:\n")
|
||||
for shelf in result['data']:
|
||||
print(f" [{shelf['id']}] {shelf['name']}")
|
||||
|
||||
def get_shelf(args):
|
||||
"""Get shelf details"""
|
||||
result = api_call("GET", f"shelves/{args.id}")
|
||||
print(f"📁 Shelf: {result['name']}")
|
||||
print(f" ID: {result['id']}")
|
||||
if result.get('description'):
|
||||
print(f" Description: {result['description']}")
|
||||
if result.get('books'):
|
||||
print(f"\n Books ({len(result['books'])}):")
|
||||
for book in result['books'][:10]:
|
||||
print(f" 📚 [{book['id']}] {book['name']}")
|
||||
|
||||
def create_shelf(args):
|
||||
"""Create a new shelf"""
|
||||
data = {
|
||||
"name": args.name,
|
||||
"description": args.description
|
||||
}
|
||||
result = api_call("POST", "shelves", data)
|
||||
print(f"✅ Shelf created: {result['name']} (ID: {result['id']})")
|
||||
|
||||
# ============ SEARCH ============
|
||||
|
||||
def search(args):
|
||||
"""Search content"""
|
||||
params = {
|
||||
'query': args.query,
|
||||
'count': args.count or 20
|
||||
}
|
||||
if args.type:
|
||||
params['query'] = f"{{{args.type}}} {args.query}"
|
||||
|
||||
result = api_call("GET", "search", params=params)
|
||||
|
||||
if not result.get('data'):
|
||||
print(f"🔍 No results for: {args.query}")
|
||||
return
|
||||
|
||||
print(f"🔍 {result.get('total', len(result['data']))} Results for '{args.query}':\n")
|
||||
for item in result['data']:
|
||||
icon = {'page': '📄', 'chapter': '📑', 'book': '📚', 'bookshelf': '📁'}.get(item['type'], '📎')
|
||||
print(f" {icon} [{item['type']}:{item['id']}] {item['name']}")
|
||||
if item.get('preview_html'):
|
||||
import re
|
||||
preview = re.sub('<[^<]+?>', '', item['preview_html'].get('content', ''))
|
||||
preview = ' '.join(preview.split())[:80]
|
||||
if preview:
|
||||
print(f" {preview}...")
|
||||
|
||||
# ============ MAIN ============
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='BookStack API CLI')
|
||||
subparsers = parser.add_subparsers(dest='command', help='Commands')
|
||||
|
||||
# Books
|
||||
p = subparsers.add_parser('list_books', help='List all books')
|
||||
p.add_argument('--count', type=int, help='Max results')
|
||||
p.set_defaults(func=list_books)
|
||||
|
||||
p = subparsers.add_parser('get_book', help='Get book details')
|
||||
p.add_argument('id', type=int)
|
||||
p.set_defaults(func=get_book)
|
||||
|
||||
p = subparsers.add_parser('create_book', help='Create a book')
|
||||
p.add_argument('name')
|
||||
p.add_argument('description', nargs='?')
|
||||
p.set_defaults(func=create_book)
|
||||
|
||||
p = subparsers.add_parser('update_book', help='Update a book')
|
||||
p.add_argument('id', type=int)
|
||||
p.add_argument('--name')
|
||||
p.add_argument('--description')
|
||||
p.set_defaults(func=update_book)
|
||||
|
||||
p = subparsers.add_parser('delete_book', help='Delete a book')
|
||||
p.add_argument('id', type=int)
|
||||
p.set_defaults(func=delete_book)
|
||||
|
||||
# Chapters
|
||||
p = subparsers.add_parser('list_chapters', help='List all chapters')
|
||||
p.add_argument('--count', type=int)
|
||||
p.set_defaults(func=list_chapters)
|
||||
|
||||
p = subparsers.add_parser('get_chapter', help='Get chapter details')
|
||||
p.add_argument('id', type=int)
|
||||
p.set_defaults(func=get_chapter)
|
||||
|
||||
p = subparsers.add_parser('create_chapter', help='Create a chapter')
|
||||
p.add_argument('--book-id', type=int, required=True)
|
||||
p.add_argument('--name', required=True)
|
||||
p.add_argument('--description')
|
||||
p.set_defaults(func=create_chapter)
|
||||
|
||||
p = subparsers.add_parser('update_chapter', help='Update a chapter')
|
||||
p.add_argument('id', type=int)
|
||||
p.add_argument('--name')
|
||||
p.add_argument('--description')
|
||||
p.add_argument('--book-id', type=int)
|
||||
p.set_defaults(func=update_chapter)
|
||||
|
||||
p = subparsers.add_parser('delete_chapter', help='Delete a chapter')
|
||||
p.add_argument('id', type=int)
|
||||
p.set_defaults(func=delete_chapter)
|
||||
|
||||
# Pages
|
||||
p = subparsers.add_parser('list_pages', help='List all pages')
|
||||
p.add_argument('--count', type=int)
|
||||
p.set_defaults(func=list_pages)
|
||||
|
||||
p = subparsers.add_parser('get_page', help='Get page with content')
|
||||
p.add_argument('id', type=int)
|
||||
p.add_argument('--content', action='store_true', help='Show full HTML')
|
||||
p.add_argument('--markdown', action='store_true', help='Show as markdown')
|
||||
p.set_defaults(func=get_page)
|
||||
|
||||
p = subparsers.add_parser('create_page', help='Create a page')
|
||||
p.add_argument('--name', required=True)
|
||||
p.add_argument('--book-id', type=int)
|
||||
p.add_argument('--chapter-id', type=int)
|
||||
p.add_argument('--content', help='Content (auto-detect HTML/MD)')
|
||||
p.add_argument('--html', help='HTML content')
|
||||
p.add_argument('--markdown', help='Markdown content')
|
||||
p.set_defaults(func=create_page)
|
||||
|
||||
p = subparsers.add_parser('update_page', help='Update a page')
|
||||
p.add_argument('id', type=int)
|
||||
p.add_argument('--name')
|
||||
p.add_argument('--content')
|
||||
p.add_argument('--html')
|
||||
p.add_argument('--markdown')
|
||||
p.add_argument('--book-id', type=int)
|
||||
p.add_argument('--chapter-id', type=int)
|
||||
p.set_defaults(func=update_page)
|
||||
|
||||
p = subparsers.add_parser('delete_page', help='Delete a page')
|
||||
p.add_argument('id', type=int)
|
||||
p.set_defaults(func=delete_page)
|
||||
|
||||
# Shelves
|
||||
p = subparsers.add_parser('list_shelves', help='List all shelves')
|
||||
p.add_argument('--count', type=int)
|
||||
p.set_defaults(func=list_shelves)
|
||||
|
||||
p = subparsers.add_parser('get_shelf', help='Get shelf details')
|
||||
p.add_argument('id', type=int)
|
||||
p.set_defaults(func=get_shelf)
|
||||
|
||||
p = subparsers.add_parser('create_shelf', help='Create a shelf')
|
||||
p.add_argument('name')
|
||||
p.add_argument('description', nargs='?')
|
||||
p.set_defaults(func=create_shelf)
|
||||
|
||||
# Search
|
||||
p = subparsers.add_parser('search', help='Search content')
|
||||
p.add_argument('query')
|
||||
p.add_argument('--type', choices=['page', 'chapter', 'book', 'shelf'])
|
||||
p.add_argument('--count', type=int)
|
||||
p.set_defaults(func=search)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
args.func(args)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user