package main import ( "context" "errors" "fmt" "os" "path/filepath" "strconv" "strings" "codex-telegram-bot/internal/store" ) func main() { if err := run(context.Background(), os.Args[1:]); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } } func run(ctx context.Context, args []string) error { if len(args) == 0 { return usage() } dbPath := os.Getenv("DB_PATH") if dbPath == "" { dbPath = filepath.Join("data", "bot.db") } st, err := store.Open(ctx, dbPath) if err != nil { return err } defer st.Close() switch args[0] { case "allow-user": return allowUser(ctx, st, args[1:]) case "remove-user": return removeUser(ctx, st, args[1:]) case "list-users": return listUsers(ctx, st) case "add-workspace": return addWorkspace(ctx, st, args[1:]) case "list-workspaces": return listWorkspaces(ctx, st) default: return usage() } } func usage() error { return errors.New(`usage: admin allow-user TELEGRAM_USER_ID [username] [notes...] admin remove-user TELEGRAM_USER_ID admin list-users admin add-workspace ABSOLUTE_PATH [label] [--default] admin list-workspaces`) } func allowUser(ctx context.Context, st *store.Store, args []string) error { if len(args) < 1 { return errors.New("allow-user requires TELEGRAM_USER_ID") } userID, err := strconv.ParseInt(args[0], 10, 64) if err != nil { return fmt.Errorf("invalid telegram user id: %w", err) } username := "" notes := "" if len(args) >= 2 { username = args[1] } if len(args) >= 3 { notes = strings.Join(args[2:], " ") } if err := st.AddAllowedUser(ctx, userID, username, notes); err != nil { return err } fmt.Printf("allowed user %d\n", userID) return nil } func removeUser(ctx context.Context, st *store.Store, args []string) error { if len(args) != 1 { return errors.New("remove-user requires TELEGRAM_USER_ID") } userID, err := strconv.ParseInt(args[0], 10, 64) if err != nil { return fmt.Errorf("invalid telegram user id: %w", err) } if err := st.RemoveAllowedUser(ctx, userID); err != nil { return err } fmt.Printf("removed user %d\n", userID) return nil } func listUsers(ctx context.Context, st *store.Store) error { users, err := st.ListAllowedUsers(ctx) if err != nil { return err } if len(users) == 0 { fmt.Println("no allowed users") return nil } for _, user := range users { if user.Username == "" && user.Notes == "" { fmt.Printf("%d\n", user.TelegramUserID) continue } fmt.Printf("%d\t%s\t%s\n", user.TelegramUserID, user.Username, user.Notes) } return nil } func addWorkspace(ctx context.Context, st *store.Store, args []string) error { if len(args) < 1 { return errors.New("add-workspace requires ABSOLUTE_PATH") } path := args[0] label := "" isDefault := false for _, arg := range args[1:] { if arg == "--default" { isDefault = true continue } if label == "" { label = arg continue } label += " " + arg } clean, err := store.ValidateWorkspacePath(path) if err != nil { return err } info, err := os.Stat(clean) if err != nil { return fmt.Errorf("workspace path is not accessible: %w", err) } if !info.IsDir() { return errors.New("workspace path must be a directory") } workspace, err := st.AddWorkspace(ctx, clean, label, isDefault) if err != nil { return err } fmt.Printf("workspace %d\t%s\t%s\n", workspace.ID, workspace.Label, workspace.Path) return nil } func listWorkspaces(ctx context.Context, st *store.Store) error { workspaces, err := st.ListWorkspaces(ctx) if err != nil { return err } if len(workspaces) == 0 { fmt.Println("no workspaces") return nil } for _, workspace := range workspaces { marker := "" if workspace.IsDefault { marker = "default" } fmt.Printf("%d\t%s\t%s\t%s\n", workspace.ID, marker, workspace.Label, workspace.Path) } return nil }