github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/juju/user/info.go (about) 1 // Copyright 2012-2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for infos. 3 4 package user 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/cmd" 11 "github.com/juju/errors" 12 "launchpad.net/gnuflag" 13 14 "github.com/juju/juju/api/usermanager" 15 "github.com/juju/juju/apiserver/params" 16 ) 17 18 const InfoCommandDoc = ` 19 Display infomation on a user. 20 21 Examples: 22 # Show information on the current user 23 $ juju user info 24 user-name: foobar 25 display-name: Foo Bar 26 date-created : 1981-02-27 16:10:05 +0000 UTC 27 last-connection: 2014-01-01 00:00:00 +0000 UTC 28 29 # Show information on a user with the given username 30 $ juju user info jsmith 31 user-name: jsmith 32 display-name: John Smith 33 date-created : 1981-02-27 16:10:05 +0000 UTC 34 last-connection: 2014-01-01 00:00:00 +0000 UTC 35 36 # Show information on the current user in JSON format 37 $ juju user info --format json 38 {"user-name":"foobar", 39 "display-name":"Foo Bar", 40 "date-created": "1981-02-27 16:10:05 +0000 UTC", 41 "last-connection": "2014-01-01 00:00:00 +0000 UTC"} 42 43 # Show information on the current user in YAML format 44 $ juju user info --format yaml 45 user-name: foobar 46 display-name: Foo Bar 47 date-created : 1981-02-27 16:10:05 +0000 UTC 48 last-connection: 2014-01-01 00:00:00 +0000 UTC 49 ` 50 51 // UserInfoAPI defines the API methods that the info command uses. 52 type UserInfoAPI interface { 53 UserInfo([]string, usermanager.IncludeDisabled) ([]params.UserInfo, error) 54 Close() error 55 } 56 57 // InfoCommandBase is a common base for 'juju user info' and 'juju user list'. 58 type InfoCommandBase struct { 59 UserCommandBase 60 api UserInfoAPI 61 exactTime bool 62 out cmd.Output 63 } 64 65 func (c *InfoCommandBase) SetFlags(f *gnuflag.FlagSet) { 66 f.BoolVar(&c.exactTime, "exact-time", false, "use full timestamp precision") 67 } 68 69 // InfoCommand retrieves information about a single user. 70 type InfoCommand struct { 71 InfoCommandBase 72 Username string 73 } 74 75 // UserInfo defines the serialization behaviour of the user information. 76 type UserInfo struct { 77 Username string `yaml:"user-name" json:"user-name"` 78 DisplayName string `yaml:"display-name" json:"display-name"` 79 DateCreated string `yaml:"date-created" json:"date-created"` 80 LastConnection string `yaml:"last-connection" json:"last-connection"` 81 Disabled bool `yaml:"disabled,omitempty" json:"disabled,omitempty"` 82 } 83 84 // Info implements Command.Info. 85 func (c *InfoCommand) Info() *cmd.Info { 86 return &cmd.Info{ 87 Name: "info", 88 Args: "<username>", 89 Purpose: "shows information on a user", 90 Doc: InfoCommandDoc, 91 } 92 } 93 94 // SetFlags implements Command.SetFlags. 95 func (c *InfoCommand) SetFlags(f *gnuflag.FlagSet) { 96 c.InfoCommandBase.SetFlags(f) 97 c.out.AddFlags(f, "yaml", cmd.DefaultFormatters) 98 } 99 100 // Init implements Command.Init. 101 func (c *InfoCommand) Init(args []string) (err error) { 102 c.Username, err = cmd.ZeroOrOneArgs(args) 103 return err 104 } 105 106 func (c *InfoCommandBase) getUserInfoAPI() (UserInfoAPI, error) { 107 if c.api != nil { 108 return c.api, nil 109 } 110 return c.NewUserManagerAPIClient() 111 } 112 113 // Run implements Command.Run. 114 func (c *InfoCommand) Run(ctx *cmd.Context) (err error) { 115 client, err := c.getUserInfoAPI() 116 if err != nil { 117 return err 118 } 119 defer client.Close() 120 username := c.Username 121 if username == "" { 122 info, err := c.ConnectionCredentials() 123 if err != nil { 124 return err 125 } 126 username = info.User 127 } 128 result, err := client.UserInfo([]string{username}, false) 129 if err != nil { 130 return err 131 } 132 // Don't output the params type, be explicit. We convert before checking 133 // length because we want to reuse the conversion function, and we are 134 // pretty sure that there is one value there. 135 output := c.apiUsersToUserInfoSlice(result) 136 if len(output) != 1 { 137 return errors.Errorf("expected 1 result, got %d", len(output)) 138 } 139 return c.out.Write(ctx, output[0]) 140 } 141 142 func (c *InfoCommandBase) apiUsersToUserInfoSlice(users []params.UserInfo) []UserInfo { 143 var output []UserInfo 144 var now = time.Now() 145 for _, info := range users { 146 outInfo := UserInfo{ 147 Username: info.Username, 148 DisplayName: info.DisplayName, 149 Disabled: info.Disabled, 150 LastConnection: LastConnection(info.LastConnection, now, c.exactTime), 151 } 152 if c.exactTime { 153 outInfo.DateCreated = info.DateCreated.String() 154 } else { 155 outInfo.DateCreated = UserFriendlyDuration(info.DateCreated, now) 156 } 157 158 output = append(output, outInfo) 159 } 160 161 return output 162 } 163 164 // LastConnection turns the *time.Time returned from the API server 165 // into a user facing string with either exact time or a user friendly 166 // string based on the args. 167 func LastConnection(connectionTime *time.Time, now time.Time, exact bool) string { 168 if connectionTime == nil { 169 return "never connected" 170 } 171 if exact { 172 return connectionTime.String() 173 } 174 return UserFriendlyDuration(*connectionTime, now) 175 } 176 177 // UserFriendlyDuration translates a time in the past into a user 178 // friendly string representation relative to the "now" time argument. 179 func UserFriendlyDuration(when, now time.Time) string { 180 since := now.Sub(when) 181 // if over 24 hours ago, just say the date. 182 if since.Hours() >= 24 { 183 return when.Format("2006-01-02") 184 } 185 if since.Hours() >= 1 { 186 unit := "hours" 187 if int(since.Hours()) == 1 { 188 unit = "hour" 189 } 190 return fmt.Sprintf("%d %s ago", int(since.Hours()), unit) 191 } 192 if since.Minutes() >= 1 { 193 unit := "minutes" 194 if int(since.Minutes()) == 1 { 195 unit = "minute" 196 } 197 return fmt.Sprintf("%d %s ago", int(since.Minutes()), unit) 198 } 199 if since.Seconds() >= 2 { 200 return fmt.Sprintf("%d seconds ago", int(since.Seconds())) 201 } 202 return "just now" 203 }