1
0

login.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package cmd
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "gogs.dmsc.dev/arp/arp_cli/client"
  7. "gogs.dmsc.dev/arp/arp_cli/config"
  8. "github.com/AlecAivazis/survey/v2"
  9. "github.com/urfave/cli/v3"
  10. )
  11. // LoginCommand returns the login command
  12. func LoginCommand() *cli.Command {
  13. return &cli.Command{
  14. Name: "login",
  15. Usage: "Authenticate with the ARP server",
  16. Description: `Login to an ARP server using email and password.
  17. This command will store the authentication token in ~/.arp_cli/config.json
  18. for use by subsequent commands.
  19. Examples:
  20. # Login with URL and email specified
  21. arp_cli login --url http://localhost:8080/query --email user@example.com
  22. # Login interactively (will prompt for all fields)
  23. arp_cli login`,
  24. Flags: []cli.Flag{
  25. &cli.StringFlag{
  26. Name: "url",
  27. Aliases: []string{"u"},
  28. Usage: "ARP server URL",
  29. Sources: cli.EnvVars("ARP_URL"),
  30. },
  31. &cli.StringFlag{
  32. Name: "email",
  33. Aliases: []string{"e"},
  34. Usage: "User email address",
  35. },
  36. &cli.StringFlag{
  37. Name: "password",
  38. Aliases: []string{"p"},
  39. Usage: "User password (will prompt if not provided)",
  40. },
  41. },
  42. Action: doLogin,
  43. }
  44. }
  45. func doLogin(ctx context.Context, cmd *cli.Command) error {
  46. // Get URL
  47. serverURL := cmd.String("url")
  48. if serverURL == "" {
  49. cfg, err := config.Load()
  50. if err != nil {
  51. return fmt.Errorf("failed to load config: %w", err)
  52. }
  53. serverURL = cfg.ServerURL
  54. }
  55. // Prompt for URL if still empty
  56. if serverURL == "" {
  57. prompt := &survey.Input{
  58. Message: "Server URL",
  59. Help: "The GraphQL endpoint URL (e.g., http://localhost:8080/query)",
  60. }
  61. if err := survey.AskOne(prompt, &serverURL, survey.WithValidator(survey.Required)); err != nil {
  62. return err
  63. }
  64. }
  65. // Get email
  66. email := cmd.String("email")
  67. if email == "" {
  68. prompt := &survey.Input{
  69. Message: "Email",
  70. Help: "Your user account email address",
  71. }
  72. if err := survey.AskOne(prompt, &email, survey.WithValidator(survey.Required)); err != nil {
  73. return err
  74. }
  75. }
  76. // Get password
  77. password := cmd.String("password")
  78. if password == "" {
  79. prompt := &survey.Password{
  80. Message: "Password",
  81. Help: "Your user account password",
  82. }
  83. if err := survey.AskOne(prompt, &password, survey.WithValidator(survey.Required)); err != nil {
  84. return err
  85. }
  86. }
  87. // Perform login
  88. c := client.New(serverURL)
  89. query := `
  90. mutation Login($email: String!, $password: String!) {
  91. login(email: $email, password: $password) {
  92. token
  93. user {
  94. id
  95. email
  96. roles {
  97. id
  98. name
  99. }
  100. }
  101. }
  102. }`
  103. variables := map[string]interface{}{
  104. "email": email,
  105. "password": password,
  106. }
  107. resp, err := c.Mutation(query, variables)
  108. if err != nil {
  109. return fmt.Errorf("login failed: %w", err)
  110. }
  111. // Parse response
  112. var loginResp struct {
  113. Login struct {
  114. Token string `json:"token"`
  115. User struct {
  116. ID string `json:"id"`
  117. Email string `json:"email"`
  118. Roles []struct {
  119. ID string `json:"id"`
  120. Name string `json:"name"`
  121. } `json:"roles"`
  122. } `json:"user"`
  123. } `json:"login"`
  124. }
  125. if err := json.Unmarshal(resp.Data, &loginResp); err != nil {
  126. return fmt.Errorf("failed to parse response: %w", err)
  127. }
  128. // Save config
  129. cfg, err := config.Load()
  130. if err != nil {
  131. return fmt.Errorf("failed to load config: %w", err)
  132. }
  133. cfg.ServerURL = serverURL
  134. cfg.Token = loginResp.Login.Token
  135. cfg.UserEmail = loginResp.Login.User.Email
  136. if err := config.Save(cfg); err != nil {
  137. return fmt.Errorf("failed to save config: %w", err)
  138. }
  139. fmt.Printf("Logged in as %s\n", loginResp.Login.User.Email)
  140. if len(loginResp.Login.User.Roles) > 0 {
  141. fmt.Print("Roles: ")
  142. for i, role := range loginResp.Login.User.Roles {
  143. if i > 0 {
  144. fmt.Print(", ")
  145. }
  146. fmt.Print(role.Name)
  147. }
  148. fmt.Println()
  149. }
  150. return nil
  151. }