feat: initial commit

This commit is contained in:
2025-09-11 23:31:07 +03:00
commit a146c2423c
4 changed files with 200 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
poetry.lock

92
import.py Normal file
View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python3
import csv
import requests
import json
import argparse
import getpass
def create_card(session, domain, board_id, stack_id, title, description):
url = f"https://{domain}/index.php/apps/deck/api/v1.0/boards/{board_id}/stacks/{stack_id}/cards"
headers = {"OCS-APIRequest": "true", "Content-Type": "application/json"}
payload = {
"title": title,
"type": "plain",
"order": 0,
"description": description,
"duedate": None,
}
response = session.post(url, headers=headers, data=json.dumps(payload))
return response
def main():
parser = argparse.ArgumentParser(
description="Import tasks from a CSV file into Nextcloud Deck"
)
parser.add_argument(
"--domain",
required=True,
help="Nextcloud instance domain (e.g., example.com or https://example.com)",
)
parser.add_argument(
"--board-id",
required=True,
type=int,
help="Board ID where the cards will be created",
)
parser.add_argument(
"--stack-id",
required=True,
type=int,
help="Stack ID where the cards will be added",
)
parser.add_argument(
"--csv-file", required=True, help="Path to the CSV file containing tasks"
)
parser.add_argument(
"--username", help="Nextcloud username (if not provided, will be prompted)"
)
parser.add_argument(
"--password",
help="Nextcloud password or app password (if not provided, will be prompted)",
)
args = parser.parse_args()
# Prompt for credentials if missing
username = args.username or input("Nextcloud username: ")
password = args.password or getpass.getpass(
"Nextcloud password (or app password): "
)
session = requests.Session()
session.auth = (username, password)
with open(args.csv_file, newline="", encoding="utf-8") as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
title = row.get("title", "").strip()
description = row.get("description", "").strip()
if not title:
print(f"Skipping row with missing title: {row}")
continue
response = create_card(
session, args.domain, args.board_id, args.stack_id, title, description
)
if response.status_code in (200, 201):
print(f"✔️ Successfully created card: {title}")
else:
print(
f"❌ Failed to create card: {title} - Error: {response.status_code} {response.text}"
)
if __name__ == "__main__":
main()

90
list_stacks.py Normal file
View File

@@ -0,0 +1,90 @@
#!/usr/bin/env python3
import argparse
import json
import sys
import requests
from urllib.parse import urlparse
import getpass
def normalize_base_url(domain_or_url: str) -> str:
parsed = urlparse(domain_or_url)
if parsed.scheme in ("http", "https"):
return domain_or_url.rstrip("/")
return f"https://{domain_or_url.strip().strip('/')}"
def list_stacks(session: requests.Session, base_url: str, board_id: int):
url = f"{base_url}/index.php/apps/deck/api/v1.0/boards/{board_id}/stacks"
headers = {"OCS-APIRequest": "true", "Accept": "application/json"}
resp = session.get(url, headers=headers)
if resp.status_code != 200:
raise RuntimeError(f"Deck API error: {resp.status_code} {resp.text}")
return resp.json()
def main():
parser = argparse.ArgumentParser(
description="List stacks (id + name) for a Nextcloud Deck board."
)
parser.add_argument(
"--domain",
required=True,
help="Nextcloud instance (e.g., example.com or https://example.com)",
)
parser.add_argument(
"--board-id", required=True, type=int, help="Deck Board ID to list stacks from"
)
parser.add_argument(
"--username", help="Nextcloud username (if not provided, will be prompted)"
)
parser.add_argument(
"--password",
help="Nextcloud password or app password (if not provided, will be prompted)",
)
parser.add_argument(
"--json", action="store_true", help="Output raw JSON instead of a table"
)
args = parser.parse_args()
# Prompt for missing creds
username = args.username or input("Nextcloud username: ")
password = args.password or getpass.getpass(
"Nextcloud password (or app password): "
)
base_url = normalize_base_url(args.domain)
session = requests.Session()
session.auth = (username, password)
try:
stacks = list_stacks(session, base_url, args.board_id)
except Exception as e:
print(f"❌ Failed to fetch stacks: {e}", file=sys.stderr)
sys.exit(1)
if args.json:
print(json.dumps(stacks, ensure_ascii=False, indent=2))
return
if not stacks:
print("No stacks found.")
return
print(f"Stacks for board {args.board_id} at {base_url}:")
print("-" * 60)
print(f"{'ID':<8} {'NAME'}")
print("-" * 60)
for s in stacks:
sid = s.get("id")
title = s.get("title", "")
print(f"{str(sid):<8} {title}")
print("-" * 60)
print("Tip: use the ID in your importer script's --stack-id.")
if __name__ == "__main__":
main()

17
pyproject.toml Normal file
View File

@@ -0,0 +1,17 @@
[project]
name = "nextcloud-deck-tools"
version = "0.1.0"
description = ""
authors = [
{name = "Chen Asraf",email = "casraf@pm.me"}
]
readme = "README.md"
requires-python = "^3.11"
dependencies = [
"requests (>=2.32.5,<3.0.0)"
]
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"