From 3c6857e6158c376aee48f87f3649c67ffa44883a Mon Sep 17 00:00:00 2001 From: Niklas Meinzer Date: Sun, 28 Jun 2026 10:11:38 +0200 Subject: [PATCH] Add user import --- src/allmende_payment_system/api/admin.py | 4 +- src/allmende_payment_system/cli.py | 80 ++++++++++++++++++++---- src/allmende_payment_system/tools.py | 4 +- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/allmende_payment_system/api/admin.py b/src/allmende_payment_system/api/admin.py index b62f28f..46867fd 100644 --- a/src/allmende_payment_system/api/admin.py +++ b/src/allmende_payment_system/api/admin.py @@ -193,7 +193,9 @@ async def get_products( user: UserDep, ): products = session.scalars( - select(Product).order_by(Product.area_id, Product.name) + select(Product) + .join(ProductDetails) + .order_by(Product.area_id, ProductDetails.name) ).all() templates = get_jinja_renderer() diff --git a/src/allmende_payment_system/cli.py b/src/allmende_payment_system/cli.py index 0e336e4..83923ab 100644 --- a/src/allmende_payment_system/cli.py +++ b/src/allmende_payment_system/cli.py @@ -1,9 +1,9 @@ import argparse -from collections import defaultdict import csv +import sys +from collections import defaultdict from datetime import datetime, time from decimal import Decimal -import sys from sqlalchemy import select @@ -12,10 +12,10 @@ from allmende_payment_system.models import ( Account, Order, OrderItem, + Product, ProductDetails, Transaction, - Order, - Product, + User, ) @@ -26,7 +26,7 @@ def init_db(): print("Database initialized and tables created successfully.") -def import_csv(filepath: str): +def import_transactions(filepath: str): """ Import CSV data from Grist into the database. @@ -146,7 +146,7 @@ def import_csv(filepath: str): order.transaction._total_amount = Decimal(order.total_amount) elif transaction_type == "einzahlung" or transaction_type == "einkauf": transaction = Transaction( - type="deposit", + type="deposit" if transaction_type == "einzahlung" else "expense", timestamp=datetime.combine(row["datum"], time(12, 0, 0)), _total_amount=row["betrag"], account_id=account.id, @@ -165,20 +165,78 @@ def import_csv(filepath: str): db.commit() +def import_users(filepath: str): + """ + Import user data from a CSV file into the database. + + This can be deleted after the initial import, it's just a one-time helper function to get the existing data into the system. + """ + REQUIRED_COLUMNS = {"username", "firstname", "lastname"} + + with open(filepath, newline="", encoding="utf-8") as f: + reader = csv.DictReader(f, delimiter=";") + + if not REQUIRED_COLUMNS.issubset(reader.fieldnames): + missing = REQUIRED_COLUMNS - set(reader.fieldnames) + raise ValueError(f"CSV is missing required columns: {missing}") + + user_data = [] + for i, row in enumerate(reader, start=2): # start=2 to account for header row + try: + user_data.append( + { + "username": row["username"].strip(), + "display_name": row["firstname"].strip() + + " " + + row["lastname"].strip(), + } + ) + except ValueError as e: + raise ValueError(f"Error in row {i}: {e}") + + print(f"Parsed {len(user_data)} rows successfully.") + + db = SessionLocal() + + for entry in user_data: + user = db.execute( + select(User).where(User.username == entry["username"]) + ).scalar_one_or_none() + + if not user: + user = User( + username=entry["username"], + display_name=entry["display_name"], + ) + db.add(user) + db.flush() + + db.commit() + + def main(): parser = argparse.ArgumentParser(description="Allmende Payment System CLI") subparsers = parser.add_subparsers(dest="command", help="Available subcommands") subparsers.add_parser("init-db", help="Initialize the database and create tables") - import_csv_parser = subparsers.add_parser( - "import-csv", help="Import data from a CSV file" + import_transactions_parser = subparsers.add_parser( + "import-transactions", help="Import transaction data from a CSV file" ) - import_csv_parser.add_argument("filepath", help="Path to the CSV file to import") + import_transactions_parser.add_argument( + "filepath", help="Path to the CSV file to import" + ) + + import_users_parser = subparsers.add_parser( + "import-users", help="Import user data from a CSV file" + ) + import_users_parser.add_argument("filepath", help="Path to the CSV file to import") args = parser.parse_args() if args.command == "init-db": init_db() - elif args.command == "import-csv": - import_csv(args.filepath) + elif args.command == "import-transactions": + import_transactions(args.filepath) + elif args.command == "import-users": + import_users(args.filepath) diff --git a/src/allmende_payment_system/tools.py b/src/allmende_payment_system/tools.py index e48a1e6..23e040f 100644 --- a/src/allmende_payment_system/tools.py +++ b/src/allmende_payment_system/tools.py @@ -46,7 +46,9 @@ def timer_context(name: str): return Timer() -import cProfile, pstats, io +import cProfile +import io +import pstats from contextlib import contextmanager