mirror of
https://github.com/chenasraf/nextcloud-deck-tools.git
synced 2026-05-17 17:28:07 +00:00
refactor: extract common & use env vars more
This commit is contained in:
150
import.py
150
import.py
@@ -1,97 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
import csv
|
||||
import requests
|
||||
import json
|
||||
from __future__ import annotations
|
||||
import argparse
|
||||
import getpass
|
||||
import os
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
from typing import Dict, Any
|
||||
|
||||
from common import (
|
||||
add_common_args,
|
||||
build_session,
|
||||
normalize_base_url,
|
||||
resolve_arg,
|
||||
resolve_common,
|
||||
)
|
||||
|
||||
|
||||
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"
|
||||
def create_card(
|
||||
session: requests.Session,
|
||||
base_url: str,
|
||||
board_id: int,
|
||||
stack_id: int,
|
||||
title: str,
|
||||
description: str,
|
||||
) -> requests.Response:
|
||||
url = f"{base_url}/index.php/apps/deck/api/v1.0/boards/{board_id}/stacks/{stack_id}/cards"
|
||||
headers = {"OCS-APIRequest": "true", "Content-Type": "application/json"}
|
||||
payload = {
|
||||
payload: Dict[str, Any] = {
|
||||
"title": title,
|
||||
"type": "plain",
|
||||
"order": 0,
|
||||
"description": description,
|
||||
"duedate": None,
|
||||
}
|
||||
|
||||
response = session.post(url, headers=headers, data=json.dumps(payload))
|
||||
return response
|
||||
return session.post(url, headers=headers, data=json.dumps(payload))
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
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",
|
||||
description="Import tasks from a CSV file into Nextcloud Deck."
|
||||
)
|
||||
# Common flags (domain, board-id, username, password)
|
||||
add_common_args(parser)
|
||||
|
||||
# Script-specific flags
|
||||
parser.add_argument(
|
||||
"--stack-id",
|
||||
required=True,
|
||||
type=int,
|
||||
help="Stack ID where the cards will be added",
|
||||
help="Deck Stack ID where cards will be created",
|
||||
)
|
||||
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)",
|
||||
"--csv-file",
|
||||
help="Path to the CSV file containing tasks (expects headers: title, description)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Prompt for credentials if missing
|
||||
username = (
|
||||
os.environ["NEXTCLOUD_USERNAME"]
|
||||
or args.username
|
||||
or input("Nextcloud username: ")
|
||||
)
|
||||
password = (
|
||||
os.environ["NEXTCLOUD_PASSWORD"]
|
||||
or args.password
|
||||
or getpass.getpass("Nextcloud password (or app password): ")
|
||||
)
|
||||
# Resolve common fields (ENV -> CLI -> prompt)
|
||||
try:
|
||||
base_url, board_id, username, password = resolve_common(
|
||||
cli_domain=args.domain,
|
||||
cli_board_id=args.board_id,
|
||||
cli_username=args.username,
|
||||
cli_password=args.password,
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"❌ {e}", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
session = requests.Session()
|
||||
session.auth = (username, password)
|
||||
# Resolve script-specific fields
|
||||
try:
|
||||
stack_id = resolve_arg(
|
||||
None if args.stack_id is None else str(args.stack_id),
|
||||
["NEXTCLOUD_STACK_ID", "STACK_ID"],
|
||||
prompt_text="Deck Stack ID: ",
|
||||
cast=lambda s: int(s.strip()),
|
||||
)
|
||||
csv_file = resolve_arg(
|
||||
args.csv_file,
|
||||
["IMPORT_CSV_FILE", "CSV_FILE"],
|
||||
prompt_text="CSV file path: ",
|
||||
cast=str,
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"❌ {e}", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
with open(args.csv_file, newline="", encoding="utf-8") as csvfile:
|
||||
reader = csv.DictReader(csvfile)
|
||||
session = build_session(username, password)
|
||||
|
||||
for row in reader:
|
||||
title = row.get("title", "").strip()
|
||||
description = row.get("description", "").strip()
|
||||
# Read & import
|
||||
try:
|
||||
with open(csv_file, newline="", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
title = (row.get("title") or "").strip()
|
||||
description = (row.get("description") or "").strip()
|
||||
if not title:
|
||||
print(f"Skipping row with missing title: {row}")
|
||||
continue
|
||||
|
||||
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}"
|
||||
resp = create_card(
|
||||
session, base_url, int(board_id), int(stack_id), title, description
|
||||
)
|
||||
if resp.status_code in (200, 201):
|
||||
print(f"✔️ Created card: {title}")
|
||||
else:
|
||||
print(f"❌ Failed: {title} — {resp.status_code} {resp.text}")
|
||||
except FileNotFoundError:
|
||||
print(f"❌ CSV file not found: {csv_file}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"❌ Error during import: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user