github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/core/description/user.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package description 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/schema" 11 "gopkg.in/juju/names.v2" 12 ) 13 14 type users struct { 15 Version int `yaml:"version"` 16 Users_ []*user `yaml:"users"` 17 } 18 19 type UserArgs struct { 20 Name names.UserTag 21 DisplayName string 22 CreatedBy names.UserTag 23 DateCreated time.Time 24 LastConnection time.Time 25 Access string 26 } 27 28 func newUser(args UserArgs) *user { 29 u := &user{ 30 Name_: args.Name.Id(), 31 DisplayName_: args.DisplayName, 32 CreatedBy_: args.CreatedBy.Id(), 33 DateCreated_: args.DateCreated, 34 Access_: args.Access, 35 } 36 if !args.LastConnection.IsZero() { 37 value := args.LastConnection 38 u.LastConnection_ = &value 39 } 40 return u 41 } 42 43 type user struct { 44 Name_ string `yaml:"name"` 45 DisplayName_ string `yaml:"display-name,omitempty"` 46 CreatedBy_ string `yaml:"created-by"` 47 DateCreated_ time.Time `yaml:"date-created"` 48 Access_ string `yaml:"access"` 49 // Can't use omitempty with time.Time, it just doesn't work, 50 // so use a pointer in the struct. 51 LastConnection_ *time.Time `yaml:"last-connection,omitempty"` 52 } 53 54 // Name implements User. 55 func (u *user) Name() names.UserTag { 56 return names.NewUserTag(u.Name_) 57 } 58 59 // DisplayName implements User. 60 func (u *user) DisplayName() string { 61 return u.DisplayName_ 62 } 63 64 // CreatedBy implements User. 65 func (u *user) CreatedBy() names.UserTag { 66 return names.NewUserTag(u.CreatedBy_) 67 } 68 69 // DateCreated implements User. 70 func (u *user) DateCreated() time.Time { 71 return u.DateCreated_ 72 } 73 74 // LastConnection implements User. 75 func (u *user) LastConnection() time.Time { 76 var zero time.Time 77 if u.LastConnection_ == nil { 78 return zero 79 } 80 return *u.LastConnection_ 81 } 82 83 // Access implements User. 84 func (u *user) Access() string { 85 return u.Access_ 86 } 87 88 func importUsers(source map[string]interface{}) ([]*user, error) { 89 checker := versionedChecker("users") 90 coerced, err := checker.Coerce(source, nil) 91 if err != nil { 92 return nil, errors.Annotatef(err, "users version schema check failed") 93 } 94 valid := coerced.(map[string]interface{}) 95 96 version := int(valid["version"].(int64)) 97 importFunc, ok := userDeserializationFuncs[version] 98 if !ok { 99 return nil, errors.NotValidf("version %d", version) 100 } 101 sourceList := valid["users"].([]interface{}) 102 return importUserList(sourceList, importFunc) 103 } 104 105 func importUserList(sourceList []interface{}, importFunc userDeserializationFunc) ([]*user, error) { 106 result := make([]*user, 0, len(sourceList)) 107 for i, value := range sourceList { 108 source, ok := value.(map[string]interface{}) 109 if !ok { 110 return nil, errors.Errorf("unexpected value for user %d, %T", i, value) 111 } 112 user, err := importFunc(source) 113 if err != nil { 114 return nil, errors.Annotatef(err, "user %d", i) 115 } 116 result = append(result, user) 117 } 118 return result, nil 119 } 120 121 type userDeserializationFunc func(map[string]interface{}) (*user, error) 122 123 var userDeserializationFuncs = map[int]userDeserializationFunc{ 124 1: importUserV1, 125 } 126 127 func importUserV1(source map[string]interface{}) (*user, error) { 128 fields := schema.Fields{ 129 "name": schema.String(), 130 "display-name": schema.String(), 131 "created-by": schema.String(), 132 "read-only": schema.Bool(), 133 "date-created": schema.Time(), 134 "last-connection": schema.Time(), 135 "access": schema.String(), 136 } 137 138 // Some values don't have to be there. 139 defaults := schema.Defaults{ 140 "display-name": "", 141 "last-connection": time.Time{}, 142 "read-only": false, 143 } 144 checker := schema.FieldMap(fields, defaults) 145 coerced, err := checker.Coerce(source, nil) 146 if err != nil { 147 return nil, errors.Annotatef(err, "user v1 schema check failed") 148 } 149 valid := coerced.(map[string]interface{}) 150 // From here we know that the map returned from the schema coercion 151 // contains fields of the right type. 152 153 result := &user{ 154 Name_: valid["name"].(string), 155 DisplayName_: valid["display-name"].(string), 156 CreatedBy_: valid["created-by"].(string), 157 DateCreated_: valid["date-created"].(time.Time), 158 Access_: valid["access"].(string), 159 } 160 161 lastConn := valid["last-connection"].(time.Time) 162 if !lastConn.IsZero() { 163 result.LastConnection_ = &lastConn 164 } 165 166 return result, nil 167 168 }