Initial backup 2026-02-17

This commit is contained in:
Krilly
2026-02-17 15:50:53 +00:00
commit 8902a93add
941 changed files with 131420 additions and 0 deletions

View File

@@ -0,0 +1,199 @@
#!/usr/bin/env python3
"""
notion-apikeys - Query Notion 'API' database for API keys
Usage:
query.py <service_name> Look up a service by name
query.py --list List all entries
query.py --find-db Discover database structure/properties
query.py --setup Interactive setup (save token + db-id)
"""
import sys
import json
import os
import argparse
CONFIG_FILE = os.path.expanduser("~/.config/notion-apikeys.json")
NOTION_VERSION = "2022-06-28"
NOTION_BASE = "https://api.notion.com/v1"
def get_headers(token):
return {
"Authorization": f"Bearer {token}",
"Notion-Version": NOTION_VERSION,
"Content-Type": "application/json",
}
def notion_request(method, path, token, payload=None):
try:
import urllib.request
import urllib.error
url = f"{NOTION_BASE}{path}"
data = json.dumps(payload).encode() if payload is not None else None
req = urllib.request.Request(url, data=data, headers=get_headers(token), method=method)
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
except Exception as e:
if hasattr(e, "read"):
err = e.read().decode()
try:
err = json.loads(err)
except Exception:
pass
print(f"Notion API error: {err}", file=sys.stderr)
else:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
def find_database(token, name="API"):
result = notion_request("POST", "/search", token, {
"query": name,
"filter": {"value": "database", "property": "object"},
"page_size": 20,
})
dbs = result.get("results", [])
for db in dbs:
title_parts = db.get("title", [])
db_name = "".join(t.get("plain_text", "") for t in title_parts).strip()
if db_name.lower() == name.lower():
return db["id"], db_name, db.get("properties", {})
# If no exact match, return all found
return None, None, dbs
def query_database(token, db_id, filter_text=None):
payload = {"page_size": 100}
if filter_text:
payload["filter"] = {
"or": [
{"property": "Name", "title": {"contains": filter_text}},
]
}
return notion_request("POST", f"/databases/{db_id}/query", token, payload)
def extract_value(prop):
ptype = prop.get("type", "")
if ptype == "title":
return "".join(t.get("plain_text", "") for t in prop.get("title", []))
elif ptype == "rich_text":
return "".join(t.get("plain_text", "") for t in prop.get("rich_text", []))
elif ptype in ("url", "email", "phone_number"):
return prop.get(ptype) or ""
elif ptype == "select":
s = prop.get("select")
return s.get("name", "") if s else ""
elif ptype == "multi_select":
return ", ".join(s.get("name", "") for s in prop.get("multi_select", []))
elif ptype == "number":
v = prop.get("number")
return str(v) if v is not None else ""
elif ptype == "checkbox":
return "" if prop.get("checkbox") else ""
elif ptype == "date":
d = prop.get("date")
return d.get("start", "") if d else ""
return ""
def load_config():
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE) as f:
return json.load(f)
return {}
def save_config(config):
os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True)
with open(CONFIG_FILE, "w") as f:
json.dump(config, f, indent=2)
def main():
parser = argparse.ArgumentParser(description="Notion API key lookup")
parser.add_argument("service", nargs="?", help="Service name to look up")
parser.add_argument("--list", action="store_true", help="List all entries")
parser.add_argument("--find-db", action="store_true", help="Discover DB structure")
parser.add_argument("--setup", action="store_true", help="Save token + db-id to config")
parser.add_argument("--token", help="Notion token (overrides config/env)")
parser.add_argument("--db-id", help="Notion database ID (overrides config)")
args = parser.parse_args()
config = load_config()
token = args.token or os.environ.get("NOTION_TOKEN") or config.get("token")
db_id = args.db_id or config.get("database_id")
# Setup mode
if args.setup:
if not token:
token = input("Notion Integration Token (secret_...): ").strip()
if not db_id:
print("Finding 'API' database automatically...")
found_id, found_name, _ = find_database(token, "API")
if found_id:
print(f"Found: '{found_name}' (ID: {found_id})")
db_id = found_id
else:
db_id = input("Database ID (or leave blank to auto-find each time): ").strip()
config["token"] = token
if db_id:
config["database_id"] = db_id
save_config(config)
print(f"✓ Config saved to {CONFIG_FILE}")
return
if not token:
print("ERROR: Notion token required.", file=sys.stderr)
print(" Run: query.py --setup", file=sys.stderr)
print(" Or set: NOTION_TOKEN env var", file=sys.stderr)
sys.exit(1)
# Auto-discover database if needed
if not db_id:
found_id, found_name, found_dbs = find_database(token, "API")
if found_id:
db_id = found_id
else:
print("ERROR: Could not find 'API' database.", file=sys.stderr)
print(f"Found databases: {[d.get('id') for d in found_dbs]}", file=sys.stderr)
sys.exit(1)
# Find database structure
if args.find_db:
found_id, found_name, props = find_database(token, "API")
if found_id:
print(f"Database: '{found_name}' (ID: {found_id})")
print("Properties:")
for name, prop in props.items():
print(f"{name} ({prop.get('type', '?')})")
return
# Query
filter_text = args.service if not args.list else None
result = query_database(token, db_id, filter_text)
pages = result.get("results", [])
if not pages:
label = f" for '{args.service}'" if args.service else ""
print(f"No entries found{label}.")
return
for page in pages:
props = page.get("properties", {})
values = {k: extract_value(v) for k, v in props.items()}
name = next((values[k] for k, v in props.items() if v.get("type") == "title"), "Unknown")
print(f"\n── {name} ──")
for k, val in values.items():
if val and props[k].get("type") != "title":
# Mask long keys for security in list mode
if args.list and len(val) > 20 and k.lower() in ("key", "api key", "token", "secret", "value"):
val = val[:8] + "..." + val[-4:]
print(f" {k}: {val}")
if __name__ == "__main__":
main()