mirror of
https://github.com/openziti/zrok.git
synced 2025-01-03 12:39:07 +01:00
233 lines
5.5 KiB
Go
233 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/bubbles/textinput"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
"github.com/openziti/zrok/rest_client_zrok/account"
|
|
"github.com/openziti/zrok/rest_model_zrok"
|
|
"github.com/openziti/zrok/tui"
|
|
"github.com/openziti/zrok/util"
|
|
"github.com/openziti/zrok/zrokdir"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(newInviteCommand().cmd)
|
|
}
|
|
|
|
type inviteCommand struct {
|
|
cmd *cobra.Command
|
|
token string
|
|
tui inviteTui
|
|
}
|
|
|
|
func newInviteCommand() *inviteCommand {
|
|
cmd := &cobra.Command{
|
|
Use: "invite",
|
|
Short: "Invite a new user to zrok",
|
|
Args: cobra.ExactArgs(0),
|
|
}
|
|
command := &inviteCommand{
|
|
cmd: cmd,
|
|
tui: newInviteTui(),
|
|
}
|
|
cmd.Run = command.run
|
|
|
|
cmd.Flags().StringVar(&command.token, "token", "", "Invite token required when zrok running in token store mode")
|
|
|
|
return command
|
|
}
|
|
|
|
func (cmd *inviteCommand) run(_ *cobra.Command, _ []string) {
|
|
zrd, err := zrokdir.Load()
|
|
if err != nil {
|
|
tui.Error("error loading zrokdir", err)
|
|
}
|
|
|
|
zrok, err := zrd.Client()
|
|
if err != nil {
|
|
if !panicInstead {
|
|
cmd.endpointError(zrd.ApiEndpoint())
|
|
tui.Error("error creating zrok api client", err)
|
|
}
|
|
panic(err)
|
|
}
|
|
|
|
if _, err := tea.NewProgram(&cmd.tui).Run(); err != nil {
|
|
tui.Error("unable to run interface", err)
|
|
os.Exit(1)
|
|
}
|
|
if cmd.tui.done {
|
|
email := cmd.tui.inputs[0].Value()
|
|
|
|
req := account.NewInviteParams()
|
|
req.Body = &rest_model_zrok.InviteRequest{
|
|
Email: email,
|
|
Token: cmd.token,
|
|
}
|
|
_, err = zrok.Account.Invite(req)
|
|
if err != nil {
|
|
cmd.endpointError(zrd.ApiEndpoint())
|
|
tui.Error("error creating invitation", err)
|
|
}
|
|
|
|
fmt.Printf("invitation sent to '%v'!\n", email)
|
|
}
|
|
}
|
|
|
|
func (cmd *inviteCommand) endpointError(apiEndpoint, _ string) {
|
|
fmt.Printf("%v\n\n", tui.SeriousBusiness.Render("there was a problem creating an invitation!"))
|
|
fmt.Printf("you are trying to use the zrok service at: %v\n\n", tui.Code.Render(apiEndpoint))
|
|
fmt.Printf("%v\n\n", tui.Attention.Render("should you be using a --token? check with your instance administrator!"))
|
|
fmt.Printf("you can change your zrok service endpoint using this command:\n\n")
|
|
fmt.Printf("%v\n\n", tui.Code.Render("$ zrok config set apiEndpoint <newEndpoint>"))
|
|
fmt.Printf("(where newEndpoint is something like: %v)\n\n", tui.Code.Render("https://some.zrok.io"))
|
|
}
|
|
|
|
type inviteTui struct {
|
|
focusIndex int
|
|
msg string
|
|
inputs []textinput.Model
|
|
cursorMode textinput.CursorMode
|
|
done bool
|
|
|
|
msgOk string
|
|
msgMismatch string
|
|
focusedStyle lipgloss.Style
|
|
blurredStyle lipgloss.Style
|
|
errorStyle lipgloss.Style
|
|
cursorStyle lipgloss.Style
|
|
noStyle lipgloss.Style
|
|
helpStyle lipgloss.Style
|
|
focusedButton string
|
|
blurredButton string
|
|
}
|
|
|
|
func newInviteTui() inviteTui {
|
|
m := inviteTui{
|
|
inputs: make([]textinput.Model, 2),
|
|
}
|
|
m.focusedStyle = tui.Attention.Copy()
|
|
m.blurredStyle = tui.Code.Copy()
|
|
m.errorStyle = tui.SeriousBusiness.Copy()
|
|
m.cursorStyle = m.focusedStyle.Copy()
|
|
m.noStyle = lipgloss.NewStyle()
|
|
m.helpStyle = m.blurredStyle.Copy()
|
|
m.focusedButton = m.focusedStyle.Copy().Render("[ Submit ]")
|
|
m.blurredButton = fmt.Sprintf("[ %v ]", m.blurredStyle.Render("Submit"))
|
|
m.msgOk = m.noStyle.Render("enter and confirm your email address...")
|
|
m.msg = m.msgOk
|
|
m.msgMismatch = m.errorStyle.Render("email is invalid or does not match confirmation...")
|
|
|
|
var t textinput.Model
|
|
for i := range m.inputs {
|
|
t = textinput.New()
|
|
t.CursorStyle = m.cursorStyle
|
|
t.CharLimit = 96
|
|
|
|
switch i {
|
|
case 0:
|
|
t.Placeholder = "Email Address"
|
|
t.Focus()
|
|
t.PromptStyle = m.focusedStyle
|
|
t.TextStyle = m.focusedStyle
|
|
case 1:
|
|
t.Placeholder = "Confirm Email"
|
|
}
|
|
|
|
m.inputs[i] = t
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
func (m inviteTui) Init() tea.Cmd { return textinput.Blink }
|
|
|
|
func (m *inviteTui) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "ctrl+c", "esc":
|
|
return m, tea.Quit
|
|
|
|
case "tab", "shift+tab", "enter", "up", "down":
|
|
s := msg.String()
|
|
|
|
if s == "enter" && m.focusIndex == len(m.inputs) {
|
|
if util.IsValidEmail(m.inputs[0].Value()) && m.inputs[0].Value() == m.inputs[1].Value() {
|
|
m.done = true
|
|
return m, tea.Quit
|
|
}
|
|
m.msg = m.msgMismatch
|
|
return m, nil
|
|
}
|
|
|
|
if s == "up" || s == "shift+tab" {
|
|
m.msg = m.msgOk
|
|
m.focusIndex--
|
|
} else {
|
|
m.msg = m.msgOk
|
|
m.focusIndex++
|
|
}
|
|
|
|
if m.focusIndex > len(m.inputs) {
|
|
m.focusIndex = 0
|
|
} else if m.focusIndex < 0 {
|
|
m.focusIndex = len(m.inputs)
|
|
}
|
|
|
|
cmds := make([]tea.Cmd, len(m.inputs))
|
|
for i := 0; i <= len(m.inputs)-1; i++ {
|
|
if i == m.focusIndex {
|
|
cmds[i] = m.inputs[i].Focus()
|
|
m.inputs[i].PromptStyle = m.focusedStyle
|
|
m.inputs[i].TextStyle = m.focusedStyle
|
|
continue
|
|
}
|
|
m.inputs[i].Blur()
|
|
m.inputs[i].PromptStyle = m.noStyle
|
|
m.inputs[i].TextStyle = m.noStyle
|
|
}
|
|
|
|
return m, tea.Batch(cmds...)
|
|
}
|
|
}
|
|
|
|
cmd := m.updateInputs(msg)
|
|
|
|
return m, cmd
|
|
}
|
|
|
|
func (m *inviteTui) updateInputs(msg tea.Msg) tea.Cmd {
|
|
cmds := make([]tea.Cmd, len(m.inputs))
|
|
for i := range m.inputs {
|
|
m.inputs[i], cmds[i] = m.inputs[i].Update(msg)
|
|
}
|
|
return tea.Batch(cmds...)
|
|
}
|
|
|
|
func (m inviteTui) View() string {
|
|
var b strings.Builder
|
|
b.WriteString(fmt.Sprintf("\n%v\n\n", m.msg))
|
|
|
|
for i := range m.inputs {
|
|
b.WriteString(m.inputs[i].View())
|
|
if i < len(m.inputs)-1 {
|
|
b.WriteRune('\n')
|
|
}
|
|
}
|
|
|
|
button := &m.blurredButton
|
|
if m.focusIndex == len(m.inputs) {
|
|
button = &m.focusedButton
|
|
}
|
|
_, _ = fmt.Fprintf(&b, "\n\n%s\n\n", *button)
|
|
|
|
return b.String()
|
|
}
|