1package cmd23import (4 "strconv"5 "strings"6 "time"78 "github.com/caarlos0/duration"9 "github.com/charmbracelet/soft-serve/pkg/backend"10 "github.com/charmbracelet/soft-serve/pkg/proto"11 "github.com/dustin/go-humanize"12 "github.com/spf13/cobra"13)1415// TokenCommand returns a command that manages user access tokens.16func TokenCommand() *cobra.Command {17 cmd := &cobra.Command{18 Use: "token",19 Aliases: []string{"access-token"},20 Short: "Manage access tokens",21 }2223 var createExpiresIn string24 createCmd := &cobra.Command{25 Use: "create NAME",26 Short: "Create a new access token",27 Args: cobra.MinimumNArgs(1),28 RunE: func(cmd *cobra.Command, args []string) error {29 ctx := cmd.Context()30 be := backend.FromContext(ctx)31 name := strings.Join(args, " ")3233 user := proto.UserFromContext(ctx)34 if user == nil {35 return proto.ErrUserNotFound36 }3738 var expiresAt time.Time39 var expiresIn time.Duration40 if createExpiresIn != "" {41 d, err := duration.Parse(createExpiresIn)42 if err != nil {43 return err44 }4546 expiresIn = d47 expiresAt = time.Now().Add(d)48 }4950 token, err := be.CreateAccessToken(ctx, user, name, expiresAt)51 if err != nil {52 return err53 }5455 notice := "Access token created"56 if expiresIn != 0 {57 notice += " (expires in " + humanize.Time(expiresAt) + ")"58 }5960 cmd.PrintErrln(notice)61 cmd.Println(token)6263 return nil64 },65 }6667 createCmd.Flags().StringVar(&createExpiresIn, "expires-in", "", "Token expiration time (e.g. 1y, 3mo, 2w, 5d4h, 1h30m)")6869 listCmd := &cobra.Command{70 Use: "list",71 Aliases: []string{"ls"},72 Short: "List access tokens",73 Args: cobra.NoArgs,74 RunE: func(cmd *cobra.Command, _ []string) error {75 ctx := cmd.Context()76 be := backend.FromContext(ctx)7778 user := proto.UserFromContext(ctx)79 if user == nil {80 return proto.ErrUserNotFound81 }8283 tokens, err := be.ListAccessTokens(ctx, user)84 if err != nil {85 return err86 }8788 if len(tokens) == 0 {89 cmd.Println("No tokens found")90 return nil91 }9293 now := time.Now()94 for _, token := range tokens {95 expiresAt := "forever"96 if !token.ExpiresAt.IsZero() {97 expiresAt = token.ExpiresAt.Format(time.RFC3339)98 if now.After(token.ExpiresAt) {99 expiresAt += "(expired)"100 }101 }102 cmd.Printf("[%d]%s: %s - %s\n",103 token.ID, token.Name,104 token.CreatedAt.Format(time.RFC3339), expiresAt)105 }106107 return nil108 },109 }110111 deleteCmd := &cobra.Command{112 Use: "delete ID",113 Aliases: []string{"rm", "remove"},114 Short: "Delete an access token",115 Args: cobra.ExactArgs(1),116 RunE: func(cmd *cobra.Command, args []string) error {117 ctx := cmd.Context()118 be := backend.FromContext(ctx)119120 user := proto.UserFromContext(ctx)121 if user == nil {122 return proto.ErrUserNotFound123 }124125 id, err := strconv.ParseInt(args[0], 10, 64)126 if err != nil {127 return err128 }129130 if err := be.DeleteAccessToken(ctx, user, id); err != nil {131 return err132 }133134 cmd.PrintErrln("Access token deleted")135 return nil136 },137 }138139 cmd.AddCommand(140 createCmd,141 listCmd,142 deleteCmd,143 )144145 return cmd146}