package repl import ( "errors" "fmt" "strings" "git.lyda.ie/kevin/bulletin/ask" "git.lyda.ie/kevin/bulletin/dclish" "git.lyda.ie/kevin/bulletin/key" "git.lyda.ie/kevin/bulletin/storage" "git.lyda.ie/kevin/bulletin/this" "git.lyda.ie/kevin/bulletin/users" ) // ActionUser handles the USER command - it prints out help for all the // USER subcommands. This is new to the Go version of BULLETIN. func ActionUser(cmd *dclish.Command) error { fmt.Println(cmd.Description) return nil } // ActionUserAdd handles the `USER ADD` command. This is used to add a // new user. This is new to the Go version of BULLETIN. func ActionUserAdd(cmd *dclish.Command) error { ctx := storage.Context() login := strings.ToUpper(cmd.Args[0]) u, err := users.ValidExistingLogin(this.Q, login) if err != nil { fmt.Printf("ERROR: %s.\n", err) return nil } if u.Login != "" { fmt.Println("ERROR: User already exists.") return nil } u, err = this.Q.AddUser(ctx, storage.AddUserParams{ Login: login, Name: cmd.Args[1], }) if err != nil { fmt.Printf("ERROR: %s.\n", err) return nil } if u.Login == "" { fmt.Println("ERROR: Failed to make user; unknown reason.") return nil } return nil } // ActionUserList handles the `USER LIST` command. This lists all the // users. For now this is limited to only the admin users. // // This is new to the Go version of BULLETIN. func ActionUserList(_ *dclish.Command) error { if this.User.Admin == 0 { fmt.Println("ERROR: You are not an admin.") return nil } ctx := storage.Context() userlist, err := this.Q.ListUsers(ctx) if err != nil { fmt.Printf("ERROR: Failed to list users (%s).\n", err) return nil } for _, u := range userlist { fmt.Printf("%s\n", u) } return nil } // ActionUserDelete handles the `USER DELETE` command. This will delete // the named user. Only the admin can use this command. // // This is new to the Go version of BULLETIN. func ActionUserDelete(cmd *dclish.Command) error { if this.User.Admin == 0 { fmt.Println("ERROR: You are not an admin.") return nil } u, err := users.ValidExistingLogin(this.Q, cmd.Args[0]) if err != nil || u.Login == "" { fmt.Println("ERROR: User not found.") return nil } ctx := storage.Context() err = this.Q.DeleteUser(ctx, u.Login) if err != nil { fmt.Printf("ERROR: Failed to delete user (%s).\n", err) return nil } fmt.Println("User deleted.") return nil } func actionUserEnable(cmd *dclish.Command, disabled int64, doing string) error { if this.User.Admin == 0 { fmt.Println("ERROR: You are not an admin.") return nil } u, err := users.ValidExistingLogin(this.Q, cmd.Args[0]) if err != nil || u.Login == "" { fmt.Println("ERROR: User not found.") return nil } if u.Disabled == disabled { fmt.Printf("User already %sd.\n", doing) return nil } ctx := storage.Context() err = this.Q.UpdateUserDisabled(ctx, disabled, u.Login) if err != nil { fmt.Printf("ERROR: Failed to %s user (%s).\n", doing, err) return nil } fmt.Printf("User %sd.\n", doing) return nil } // ActionUserEnable handles the `USER ENABLE` command. This enables // a user. Only the admin can use this command. // // This is new to the Go version of BULLETIN. func ActionUserEnable(cmd *dclish.Command) error { return actionUserEnable(cmd, 0, "enable") } // ActionUserDisable handles the `USER DISABLE` command. This disables // a user. Only the admin can use this command. // // This is new to the Go version of BULLETIN. func ActionUserDisable(cmd *dclish.Command) error { return actionUserEnable(cmd, 1, "disable") } func actionUserAdmin(cmd *dclish.Command, admin int64, doing string) error { if this.User.Admin == 0 { fmt.Println("ERROR: You are not an admin.") return nil } u, err := users.ValidExistingLogin(this.Q, cmd.Args[0]) if err != nil || u.Login == "" { return errors.New("User not found") } if u.Login == this.User.Login || u.Login == "SYSTEM" { return errors.New("Invalid user given") } if u.Admin == admin { fmt.Printf("User is already %s.\n", doing) return nil } ctx := storage.Context() err = this.Q.UpdateUserAdmin(ctx, admin, u.Login) if err != nil { return fmt.Errorf("Failed to make user %s (%s)", doing, err) } fmt.Printf("User is now %s.\n", doing) return nil } // ActionUserAdmin handles the `USER ADMIN` command. This makes the given // user an admin. Only the admin can use this command. // // This is new to the Go version of BULLETIN. func ActionUserAdmin(cmd *dclish.Command) error { return actionUserAdmin(cmd, 1, "an admin") } // ActionUserNoadmin handles the `USER NOADMIN` command. This removes the // admin bit from a given user. Only the admin can use this command. // // This is new to the Go version of BULLETIN. func ActionUserNoadmin(cmd *dclish.Command) error { return actionUserAdmin(cmd, 0, "not an admin") } func actionUserMod(cmd *dclish.Command, mod int64, doing string) error { if this.User.Admin == 0 { fmt.Println("ERROR: You are not an admin.") return nil } u, err := users.ValidExistingLogin(this.Q, cmd.Args[0]) if err != nil || u.Login == "" { fmt.Println("ERROR: User not found.") return nil } if u.Moderator == mod { fmt.Printf("User is already %s.\n", doing) return nil } ctx := storage.Context() err = this.Q.UpdateUserMod(ctx, mod, u.Login) if err != nil { fmt.Printf("ERROR: Failed to make user %s (%s).\n", doing, err) return nil } fmt.Printf("User is now %s.\n", doing) return nil } // ActionUserMod handles the `USER MOD` command. Makes given the user a // moderator. Only the admin can use this command. // // This is new to the Go version of BULLETIN. func ActionUserMod(cmd *dclish.Command) error { return actionUserMod(cmd, 1, "a moderator") } // ActionUserNomod handles the `USER NOMOD` command. Removes the // moderator bit from the given user. Only the admin can use this command. // // This is new to the Go version of BULLETIN. func ActionUserNomod(cmd *dclish.Command) error { return actionUserMod(cmd, 0, "not a moderator") } // ActionUserName handles the `USER NAME` command. Updates the user's // name. Only the admin can use the two argument version of this command. // // This is new to the Go version of BULLETIN. func ActionUserName(cmd *dclish.Command) error { if len(cmd.Args) == 2 && this.User.Admin == 0 { fmt.Println("ERROR: You are not an admin.") return nil } login := this.User.Login name := cmd.Args[0] if len(cmd.Args) == 2 { login = strings.ToUpper(cmd.Args[0]) name = cmd.Args[1] _, err := users.ValidExistingLogin(this.Q, login) if err != nil { fmt.Printf("ERROR: %s.\n", err) return nil } } ctx := storage.Context() err := this.Q.UpdateUserName(ctx, name, login) if err != nil { fmt.Printf("ERROR: Failed to update user name (%s).\n", err) } return nil } // ActionSSH handles the `SSH` command. This prints the help for all the // SSH commands. These are used to manage the authorized_keys file. // These are new to the Go version of BULLETIN. func ActionSSH(cmd *dclish.Command) error { fmt.Println(cmd.Description) return nil } // ActionSSHAdd handles the `SSH ADD` command. This adds a given ssh key // to the authorized_keys file for the given user. An admin can add // a new public key for another user. // // This is new to the Go version of BULLETIN. func ActionSSHAdd(cmd *dclish.Command) error { if this.User.Admin == 0 && len(cmd.Args) == 1 { fmt.Println("ERROR: You are not an admin.") return nil } login := this.User.Login if len(cmd.Args) == 1 { login = cmd.Args[0] } u, err := users.ValidExistingLogin(this.Q, login) if err != nil || u.Login == "" { fmt.Println("ERROR: User not found.") return nil } sshkey, err := ask.GetLine("Enter ssh public key: ") if err != nil { fmt.Printf("ERROR: Failed to read ssh key (%s).\n", err) return nil } key.Add(u.Login, sshkey) fmt.Println("Key is added.") return nil } // ActionSSHList handles the `SSH LIST` command. This lists all the // public keys for this user. An admin can list public keys for another // user. // // This is new to the Go version of BULLETIN. func ActionSSHList(cmd *dclish.Command) error { if this.User.Admin == 0 && len(cmd.Args) == 1 { fmt.Println("ERROR: You are not an admin.") return nil } login := this.User.Login if len(cmd.Args) == 1 { login = cmd.Args[0] } u, err := users.ValidExistingLogin(this.Q, login) if err != nil || u.Login == "" { fmt.Println("ERROR: User not found.") return nil } keys, err := key.List(login) if err != nil { fmt.Printf("ERROR: Problem listing keys (%s).\n", err) return nil } fmt.Printf("The %d keys:\n %s\n", len(keys), strings.Join(keys, "\n ")) return nil } // ActionSSHDelete handles the `SSH DELETE` command. Removes ssh public // keys for a user. And admin can specify a different user to remove // public keys for. // // This is new to the Go version of BULLETIN. func ActionSSHDelete(cmd *dclish.Command) error { if this.User.Admin == 0 && len(cmd.Args) == 1 { fmt.Println("ERROR: You are not an admin.") return nil } login := this.User.Login if len(cmd.Args) == 1 { login = cmd.Args[0] } u, err := users.ValidExistingLogin(this.Q, login) if err != nil || u.Login == "" { fmt.Println("ERROR: User not found.") return nil } keys, err := key.List(login) if err != nil { fmt.Printf("ERROR: Problem listing keys (%s).\n", err) return nil } if len(keys) == 0 { fmt.Println("No keys to delete.") return nil } choice, err := ask.Choose("Choose a key to delete:", keys) if err != nil { fmt.Printf("ERROR: Problem choosing key (%s).\n", err) return nil } if choice < 0 { fmt.Println("Aborted.") return nil } err = key.Delete(keys[choice]) if err != nil { fmt.Printf("ERROR: Problem deleting key (%s).\n", err) return nil } fmt.Println("Key deleted.") return nil } // ActionSSHFetch handles the `SSH FETCH` command. This command pulls // public keys from code sites. It's the quickest way to // add a number of keys for a user. An admin can do this // for another user. // // This is new to the Go version of BULLETIN. func ActionSSHFetch(cmd *dclish.Command) error { login := this.User.Login sitename := cmd.Args[0] username := cmd.Args[1] if len(cmd.Args) == 3 && this.User.Admin == 0 { fmt.Println("ERROR: You are not an admin.") return nil } if len(cmd.Args) == 3 { login = cmd.Args[0] sitename = cmd.Args[1] username = cmd.Args[2] } fmt.Print(key.Fetch(login, sitename, username)) return nil }