| package tc |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import ( |
| "database/sql" |
| "encoding/json" |
| "errors" |
| "fmt" |
| "time" |
| |
| "github.com/apache/trafficcontrol/lib/go-rfc" |
| "github.com/apache/trafficcontrol/lib/go-util" |
| |
| validation "github.com/go-ozzo/ozzo-validation" |
| "github.com/go-ozzo/ozzo-validation/is" |
| ) |
| |
| // copyStringIfNotNil makes a deep copy of s - unless it's nil, in which case it |
| // just returns nil. |
| func copyStringIfNotNil(s *string) *string { |
| if s == nil { |
| return nil |
| } |
| ret := new(string) |
| *ret = *s |
| return ret |
| } |
| |
| // copyIntIfNotNil makes a deep copy of i - unless it's nil, in which case it |
| // just returns nil. |
| func copyIntIfNotNil(i *int) *int { |
| if i == nil { |
| return nil |
| } |
| ret := new(int) |
| *ret = *i |
| return ret |
| } |
| |
| // Upgrade converts a User to a UserV4 (as seen in API versions 4.x). |
| func (u User) Upgrade() UserV4 { |
| var ret UserV4 |
| ret.AddressLine1 = copyStringIfNotNil(u.AddressLine1) |
| ret.AddressLine2 = copyStringIfNotNil(u.AddressLine2) |
| ret.City = copyStringIfNotNil(u.City) |
| ret.Company = copyStringIfNotNil(u.Company) |
| ret.Country = copyStringIfNotNil(u.Country) |
| ret.Email = copyStringIfNotNil(u.Email) |
| ret.GID = copyIntIfNotNil(u.GID) |
| ret.ID = copyIntIfNotNil(u.ID) |
| ret.LocalPassword = copyStringIfNotNil(u.LocalPassword) |
| ret.PhoneNumber = copyStringIfNotNil(u.PhoneNumber) |
| ret.PostalCode = copyStringIfNotNil(u.PostalCode) |
| ret.PublicSSHKey = copyStringIfNotNil(u.PublicSSHKey) |
| ret.StateOrProvince = copyStringIfNotNil(u.StateOrProvince) |
| ret.Tenant = copyStringIfNotNil(u.Tenant) |
| ret.Token = copyStringIfNotNil(u.Token) |
| ret.UID = copyIntIfNotNil(u.UID) |
| ret.FullName = copyStringIfNotNil(u.FullName) |
| if u.LastUpdated != nil { |
| ret.LastUpdated = u.LastUpdated.Time |
| } |
| if u.NewUser != nil { |
| ret.NewUser = *u.NewUser |
| } |
| if u.RegistrationSent != nil { |
| ret.RegistrationSent = new(time.Time) |
| *ret.RegistrationSent = u.RegistrationSent.Time |
| } |
| if u.RoleName != nil { |
| ret.Role = *u.RoleName |
| } |
| if u.TenantID != nil { |
| ret.TenantID = *u.TenantID |
| } |
| if u.Username != nil { |
| ret.Username = *u.Username |
| } |
| return ret |
| } |
| |
| // Downgrade converts a UserV4 to a User (as seen in API versions < 4.0). |
| func (u UserV4) Downgrade() User { |
| var ret User |
| ret.FullName = new(string) |
| ret.FullName = u.FullName |
| ret.LastUpdated = TimeNoModFromTime(u.LastUpdated) |
| ret.NewUser = new(bool) |
| *ret.NewUser = u.NewUser |
| ret.RoleName = new(string) |
| *ret.RoleName = u.Role |
| ret.Role = nil |
| ret.TenantID = new(int) |
| *ret.TenantID = u.TenantID |
| ret.Username = new(string) |
| *ret.Username = u.Username |
| |
| ret.AddressLine1 = copyStringIfNotNil(u.AddressLine1) |
| ret.AddressLine2 = copyStringIfNotNil(u.AddressLine2) |
| ret.City = copyStringIfNotNil(u.City) |
| ret.Company = copyStringIfNotNil(u.Company) |
| ret.ConfirmLocalPassword = copyStringIfNotNil(u.LocalPassword) |
| ret.Country = copyStringIfNotNil(u.Country) |
| ret.Email = copyStringIfNotNil(u.Email) |
| ret.GID = copyIntIfNotNil(u.GID) |
| ret.ID = copyIntIfNotNil(u.ID) |
| ret.LocalPassword = copyStringIfNotNil(u.LocalPassword) |
| ret.PhoneNumber = copyStringIfNotNil(u.PhoneNumber) |
| ret.PostalCode = copyStringIfNotNil(u.PostalCode) |
| ret.PublicSSHKey = copyStringIfNotNil(u.PublicSSHKey) |
| if u.RegistrationSent != nil { |
| ret.RegistrationSent = TimeNoModFromTime(*u.RegistrationSent) |
| } |
| ret.StateOrProvince = copyStringIfNotNil(u.StateOrProvince) |
| ret.Tenant = copyStringIfNotNil(u.Tenant) |
| ret.Token = copyStringIfNotNil(u.Token) |
| ret.UID = copyIntIfNotNil(u.UID) |
| |
| return ret |
| } |
| |
| // UserCredentials contains Traffic Ops login credentials. |
| type UserCredentials struct { |
| Username string `json:"u"` |
| Password string `json:"p"` |
| } |
| |
| // UserToken represents a request payload containing a UUID token for |
| // authentication. |
| type UserToken struct { |
| Token string `json:"t"` |
| } |
| |
| // commonUserFields is unexported, but its contents are still visible when it is embedded |
| // LastUpdated is a new field for some structs. |
| type commonUserFields struct { |
| AddressLine1 *string `json:"addressLine1" db:"address_line1"` |
| AddressLine2 *string `json:"addressLine2" db:"address_line2"` |
| City *string `json:"city" db:"city"` |
| Company *string `json:"company" db:"company"` |
| Country *string `json:"country" db:"country"` |
| Email *string `json:"email" db:"email"` |
| FullName *string `json:"fullName" db:"full_name"` |
| GID *int `json:"gid"` |
| ID *int `json:"id" db:"id"` |
| NewUser *bool `json:"newUser" db:"new_user"` |
| PhoneNumber *string `json:"phoneNumber" db:"phone_number"` |
| PostalCode *string `json:"postalCode" db:"postal_code"` |
| PublicSSHKey *string `json:"publicSshKey" db:"public_ssh_key"` |
| Role *int `json:"role" db:"role"` |
| StateOrProvince *string `json:"stateOrProvince" db:"state_or_province"` |
| Tenant *string `json:"tenant"` |
| TenantID *int `json:"tenantId" db:"tenant_id"` |
| Token *string `json:"-" db:"token"` |
| UID *int `json:"uid"` |
| LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"` |
| } |
| |
| // User represents a user of Traffic Ops. |
| type User struct { |
| Username *string `json:"username" db:"username"` |
| RegistrationSent *TimeNoMod `json:"registrationSent" db:"registration_sent"` |
| LocalPassword *string `json:"localPasswd,omitempty" db:"local_passwd"` |
| ConfirmLocalPassword *string `json:"confirmLocalPasswd,omitempty" db:"confirm_local_passwd"` |
| // NOTE: RoleName db:"-" tag is required due to clashing with the DB query here: |
| // https://github.com/apache/trafficcontrol/blob/3b5dd406bf1a0bb456c062b0f6a465ec0617d8ef/traffic_ops/traffic_ops_golang/user/user.go#L197 |
| // It's done that way in order to maintain "rolename" vs "roleName" JSON field capitalization for the different users APIs. |
| RoleName *string `json:"roleName,omitempty" db:"role_name"` |
| commonUserFields |
| } |
| |
| // UserCurrent represents the profile for the authenticated user. |
| type UserCurrent struct { |
| UserName *string `json:"username"` |
| LocalUser *bool `json:"localUser"` |
| RoleName *string `json:"roleName"` |
| commonUserFields |
| } |
| |
| // ToLegacyCurrentUser will convert an APIv4 user to an APIv3 "current user" |
| // representation. A Role ID and "local user" value must be supplied, since the |
| // APIv4 User doesn't have them. |
| func (u UserV4) ToLegacyCurrentUser(roleID int, localUser bool) UserCurrent { |
| var ret UserCurrent |
| ret.FullName = new(string) |
| *ret.FullName = *u.FullName |
| ret.LastUpdated = TimeNoModFromTime(u.LastUpdated) |
| ret.NewUser = new(bool) |
| *ret.NewUser = u.NewUser |
| ret.RoleName = new(string) |
| *ret.RoleName = u.Role |
| ret.Role = new(int) |
| *ret.Role = roleID |
| ret.TenantID = new(int) |
| *ret.TenantID = u.TenantID |
| ret.Tenant = u.Tenant |
| ret.UserName = new(string) |
| *ret.UserName = u.Username |
| ret.LocalUser = new(bool) |
| *ret.LocalUser = localUser |
| ret.Token = copyStringIfNotNil(u.Token) |
| ret.AddressLine1 = copyStringIfNotNil(u.AddressLine1) |
| ret.AddressLine2 = copyStringIfNotNil(u.AddressLine2) |
| ret.City = copyStringIfNotNil(u.City) |
| ret.Company = copyStringIfNotNil(u.Company) |
| ret.Country = copyStringIfNotNil(u.Country) |
| ret.Email = copyStringIfNotNil(u.Email) |
| ret.GID = copyIntIfNotNil(u.GID) |
| ret.ID = copyIntIfNotNil(u.ID) |
| ret.UID = copyIntIfNotNil(u.UID) |
| ret.PhoneNumber = copyStringIfNotNil(u.PhoneNumber) |
| ret.PostalCode = copyStringIfNotNil(u.PostalCode) |
| ret.PublicSSHKey = copyStringIfNotNil(u.PublicSSHKey) |
| ret.StateOrProvince = copyStringIfNotNil(u.StateOrProvince) |
| ret.Tenant = copyStringIfNotNil(u.Tenant) |
| ret.Token = copyStringIfNotNil(u.Token) |
| ret.UID = copyIntIfNotNil(u.UID) |
| |
| return ret |
| } |
| |
| // UserV4 is an alias for the User struct used for the latest minor version associated with api major version 4. |
| type UserV4 UserV40 |
| |
| // A UserV40 is a representation of a Traffic Ops user as it appears in version |
| // 4.0 of Traffic Ops's API. |
| type UserV40 struct { |
| AddressLine1 *string `json:"addressLine1" db:"address_line1"` |
| AddressLine2 *string `json:"addressLine2" db:"address_line2"` |
| ChangeLogCount int `json:"changeLogCount" db:"change_log_count"` |
| City *string `json:"city" db:"city"` |
| Company *string `json:"company" db:"company"` |
| Country *string `json:"country" db:"country"` |
| Email *string `json:"email" db:"email"` |
| FullName *string `json:"fullName" db:"full_name"` |
| // Deprecated: This has no known use, and will likely be removed in future |
| // API versions. |
| GID *int `json:"gid"` |
| ID *int `json:"id" db:"id"` |
| LastAuthenticated *time.Time `json:"lastAuthenticated" db:"last_authenticated"` |
| LastUpdated time.Time `json:"lastUpdated" db:"last_updated"` |
| LocalPassword *string `json:"localPasswd,omitempty" db:"local_passwd"` |
| NewUser bool `json:"newUser" db:"new_user"` |
| PhoneNumber *string `json:"phoneNumber" db:"phone_number"` |
| PostalCode *string `json:"postalCode" db:"postal_code"` |
| PublicSSHKey *string `json:"publicSshKey" db:"public_ssh_key"` |
| RegistrationSent *time.Time `json:"registrationSent" db:"registration_sent"` |
| Role string `json:"role" db:"role"` |
| StateOrProvince *string `json:"stateOrProvince" db:"state_or_province"` |
| Tenant *string `json:"tenant"` |
| TenantID int `json:"tenantId" db:"tenant_id"` |
| Token *string `json:"-" db:"token"` |
| UCDN string `json:"ucdn"` |
| // Deprecated: This has no known use, and will likely be removed in future |
| // API versions. |
| UID *int `json:"uid"` |
| Username string `json:"username" db:"username"` |
| } |
| |
| // UsersResponseV4 is the type of a response from Traffic Ops to requests made |
| // to /users which return more than one user for the latest 4.x api version variant. |
| type UsersResponseV4 struct { |
| Response []UserV4 `json:"response"` |
| Alerts |
| } |
| |
| // UserResponseV4 is the type of a response from Traffic Ops to requests made |
| // to /users which return one user for the latest 4.x api version variant. |
| type UserResponseV4 struct { |
| Response UserV4 `json:"response"` |
| Alerts |
| } |
| |
| // CurrentUserUpdateRequest differs from a regular User/UserCurrent in that many of its fields are |
| // *parsed* but not *unmarshaled*. This allows a handler to distinguish between "null" and |
| // "undefined" values. |
| type CurrentUserUpdateRequest struct { |
| // User, for whatever reason, contains all of the actual data. |
| User *CurrentUserUpdateRequestUser `json:"user"` |
| } |
| |
| // CurrentUserUpdateRequestUser holds all of the actual data in a request to update the current user. |
| type CurrentUserUpdateRequestUser struct { |
| AddressLine1 json.RawMessage `json:"addressLine1"` |
| AddressLine2 json.RawMessage `json:"addressLine2"` |
| City json.RawMessage `json:"city"` |
| Company json.RawMessage `json:"company"` |
| ConfirmLocalPasswd *string `json:"confirmLocalPasswd"` |
| Country json.RawMessage `json:"country"` |
| Email json.RawMessage `json:"email"` |
| FullName json.RawMessage `json:"fullName"` |
| GID json.RawMessage `json:"gid"` |
| ID json.RawMessage `json:"id"` |
| LocalPasswd *string `json:"localPasswd"` |
| PhoneNumber json.RawMessage `json:"phoneNumber"` |
| PostalCode json.RawMessage `json:"postalCode"` |
| PublicSSHKey json.RawMessage `json:"publicSshKey"` |
| Role json.RawMessage `json:"role"` |
| StateOrProvince json.RawMessage `json:"stateOrProvince"` |
| TenantID json.RawMessage `json:"tenantId"` |
| UID json.RawMessage `json:"uid"` |
| Username json.RawMessage `json:"username"` |
| } |
| |
| // Upgrade converts an APIv3 and earlier "current user" to an APIv4 User. |
| // Fields not present in earlier API versions need to be passed explicitly |
| func (u UserCurrent) Upgrade(registrationSent, lastAuthenticated *time.Time, ucdn string, changeLogCount int) UserV4 { |
| var ret UserV4 |
| ret.AddressLine1 = copyStringIfNotNil(u.AddressLine1) |
| ret.AddressLine2 = copyStringIfNotNil(u.AddressLine2) |
| ret.ChangeLogCount = changeLogCount |
| ret.City = copyStringIfNotNil(u.City) |
| ret.Company = copyStringIfNotNil(u.Company) |
| ret.Country = copyStringIfNotNil(u.Country) |
| ret.Email = copyStringIfNotNil(u.Email) |
| ret.GID = copyIntIfNotNil(u.GID) |
| ret.ID = copyIntIfNotNil(u.ID) |
| ret.LastAuthenticated = lastAuthenticated |
| ret.PhoneNumber = copyStringIfNotNil(u.PhoneNumber) |
| ret.PostalCode = copyStringIfNotNil(u.PostalCode) |
| ret.PublicSSHKey = copyStringIfNotNil(u.PublicSSHKey) |
| ret.RegistrationSent = registrationSent |
| ret.StateOrProvince = copyStringIfNotNil(u.StateOrProvince) |
| ret.Tenant = copyStringIfNotNil(u.Tenant) |
| ret.Token = copyStringIfNotNil(u.Token) |
| ret.UCDN = ucdn |
| ret.UID = copyIntIfNotNil(u.UID) |
| ret.FullName = u.FullName |
| if u.LastUpdated != nil { |
| ret.LastUpdated = u.LastUpdated.Time |
| } |
| if u.NewUser != nil { |
| ret.NewUser = *u.NewUser |
| } |
| |
| if u.RoleName != nil { |
| ret.Role = *u.RoleName |
| } |
| if u.TenantID != nil { |
| ret.TenantID = *u.TenantID |
| } |
| if u.UserName != nil { |
| ret.Username = *u.UserName |
| } |
| return ret |
| } |
| |
| // UnmarshalAndValidate validates the request and returns a User into which the request's information |
| // has been unmarshalled. |
| func (u *CurrentUserUpdateRequestUser) UnmarshalAndValidate(user *User) error { |
| errs := []error{} |
| if u.AddressLine1 != nil { |
| if err := json.Unmarshal(u.AddressLine1, &user.AddressLine1); err != nil { |
| errs = append(errs, fmt.Errorf("addressLine1: %w", err)) |
| } |
| } |
| |
| if u.AddressLine2 != nil { |
| if err := json.Unmarshal(u.AddressLine2, &user.AddressLine2); err != nil { |
| errs = append(errs, fmt.Errorf("addressLine2: %w", err)) |
| } |
| } |
| |
| if u.City != nil { |
| if err := json.Unmarshal(u.City, &user.City); err != nil { |
| errs = append(errs, fmt.Errorf("city: %w", err)) |
| } |
| } |
| |
| if u.Company != nil { |
| if err := json.Unmarshal(u.Company, &user.Company); err != nil { |
| errs = append(errs, fmt.Errorf("company: %w", err)) |
| } |
| } |
| |
| user.ConfirmLocalPassword = u.ConfirmLocalPasswd |
| user.LocalPassword = u.LocalPasswd |
| |
| if u.Country != nil { |
| if err := json.Unmarshal(u.Country, &user.Country); err != nil { |
| errs = append(errs, fmt.Errorf("country: %w", err)) |
| } |
| } |
| |
| if u.Email != nil { |
| if err := json.Unmarshal(u.Email, &user.Email); err != nil { |
| errs = append(errs, fmt.Errorf("email: %w", err)) |
| } else if user.Email == nil || *user.Email == "" { |
| errs = append(errs, errors.New("email: cannot be null or an empty string")) |
| } else if err = validation.Validate(*user.Email, is.Email); err != nil { |
| errs = append(errs, err) |
| } |
| } |
| |
| if u.FullName != nil { |
| if err := json.Unmarshal(u.FullName, &user.FullName); err != nil { |
| errs = append(errs, fmt.Errorf("fullName: %w", err)) |
| } else if user.FullName == nil || *user.FullName == "" { |
| // Perl enforced this |
| errs = append(errs, errors.New("fullName: cannot be set to 'null' or empty string")) |
| } |
| } |
| |
| if u.GID != nil { |
| if err := json.Unmarshal(u.GID, &user.GID); err != nil { |
| errs = append(errs, fmt.Errorf("gid: %w", err)) |
| } |
| } |
| |
| if u.ID != nil { |
| var uid int |
| if err := json.Unmarshal(u.ID, &uid); err != nil { |
| errs = append(errs, fmt.Errorf("id: %w", err)) |
| } else if user.ID != nil && *user.ID != uid { |
| errs = append(errs, errors.New("id: cannot change user id")) |
| } else { |
| user.ID = &uid |
| } |
| } |
| |
| if u.PhoneNumber != nil { |
| if err := json.Unmarshal(u.PhoneNumber, &user.PhoneNumber); err != nil { |
| errs = append(errs, fmt.Errorf("phoneNumber: %w", err)) |
| } |
| } |
| |
| if u.PostalCode != nil { |
| if err := json.Unmarshal(u.PostalCode, &user.PostalCode); err != nil { |
| errs = append(errs, fmt.Errorf("postalCode: %w", err)) |
| } |
| } |
| |
| if u.PublicSSHKey != nil { |
| if err := json.Unmarshal(u.PublicSSHKey, &user.PublicSSHKey); err != nil { |
| errs = append(errs, fmt.Errorf("publicSshKey: %w", err)) |
| } |
| } |
| |
| if u.Role != nil { |
| if err := json.Unmarshal(u.Role, &user.Role); err != nil { |
| errs = append(errs, fmt.Errorf("role: %w", err)) |
| } else if user.Role == nil { |
| errs = append(errs, errors.New("role: cannot be null")) |
| } |
| } |
| |
| if u.StateOrProvince != nil { |
| if err := json.Unmarshal(u.StateOrProvince, &user.StateOrProvince); err != nil { |
| errs = append(errs, fmt.Errorf("stateOrProvince: %w", err)) |
| } |
| } |
| |
| if u.TenantID != nil { |
| if err := json.Unmarshal(u.TenantID, &user.TenantID); err != nil { |
| errs = append(errs, fmt.Errorf("tenantID: %w", err)) |
| } else if user.TenantID == nil { |
| errs = append(errs, errors.New("tenantID: cannot be null")) |
| } |
| } |
| |
| if u.UID != nil { |
| if err := json.Unmarshal(u.UID, &user.UID); err != nil { |
| errs = append(errs, fmt.Errorf("uid: %w", err)) |
| } |
| } |
| |
| if u.Username != nil { |
| if err := json.Unmarshal(u.Username, &user.Username); err != nil { |
| errs = append(errs, fmt.Errorf("username: %w", err)) |
| } else if user.Username == nil || *user.Username == "" { |
| errs = append(errs, errors.New("username: cannot be null or empty string")) |
| } |
| } |
| |
| return util.JoinErrs(errs) |
| } |
| |
| // ------------------- Response structs -------------------- // |
| // Response structs should only be used in the client // |
| // The client's use of these will eventually be deprecated // |
| // --------------------------------------------------------- // |
| |
| // UsersResponse can hold a Traffic Ops API response to a request to get a list of users. |
| type UsersResponse struct { |
| Response []User `json:"response"` |
| Alerts |
| } |
| |
| // UserResponse can hold a Traffic Ops API response to a request to get a user. |
| type UserResponse struct { |
| Response User `json:"response"` |
| Alerts |
| } |
| |
| // CreateUserResponse can hold a Traffic Ops API response to a POST request to create a user. |
| type CreateUserResponse struct { |
| Response User `json:"response"` |
| Alerts |
| } |
| |
| // CreateUserResponseV4 can hold a Traffic Ops API response to a POST request to create a user in api v4. |
| type CreateUserResponseV4 struct { |
| Response UserV4 `json:"response"` |
| Alerts |
| } |
| |
| // UpdateUserResponse can hold a Traffic Ops API response to a PUT request to update a user. |
| type UpdateUserResponse struct { |
| Response User `json:"response"` |
| Alerts |
| } |
| |
| // UpdateUserResponseV4 can hold a Traffic Ops API response to a PUT request to update a user for the latest 4.x api version variant. |
| type UpdateUserResponseV4 struct { |
| Response UserV4 `json:"response"` |
| Alerts |
| } |
| |
| // DeleteUserResponse can theoretically hold a Traffic Ops API response to a |
| // DELETE request to update a user. It is unused. |
| type DeleteUserResponse struct { |
| Alerts |
| } |
| |
| // UserCurrentResponse can hold a Traffic Ops API response to a request to get |
| // or update the current user. |
| type UserCurrentResponse struct { |
| Response UserCurrent `json:"response"` |
| Alerts |
| } |
| |
| // UserCurrentResponseV4 is the latest 4.x Traffic Ops API version variant of UserResponse. |
| type UserCurrentResponseV4 struct { |
| Response UserV4 `json:"response"` |
| Alerts |
| } |
| |
| // UserDeliveryServiceDeleteResponse can hold a Traffic Ops API response to |
| // a request to remove a delivery service from a user. |
| type UserDeliveryServiceDeleteResponse struct { |
| Alerts |
| } |
| |
| // UserPasswordResetRequest can hold Traffic Ops API request to reset a user's password. |
| type UserPasswordResetRequest struct { |
| Email rfc.EmailAddress `json:"email"` |
| } |
| |
| // UserRegistrationRequest is the request submitted by operators when they want to register a new |
| // user. |
| type UserRegistrationRequest struct { |
| Email rfc.EmailAddress `json:"email"` |
| // Role - despite being named "Role" - is actually merely the *ID* of a Role to give the new user. |
| Role uint `json:"role"` |
| TenantID uint `json:"tenantId"` |
| } |
| |
| // UserRegistrationRequestV4 is the alias for the UserRegistrationRequest for the latest 4.x api version variant. |
| type UserRegistrationRequestV4 UserRegistrationRequestV40 |
| |
| // UserRegistrationRequestV40 is the request submitted by operators when they want to register a new |
| // user in api V4. |
| type UserRegistrationRequestV40 struct { |
| Email rfc.EmailAddress `json:"email"` |
| Role string `json:"role"` |
| TenantID uint `json:"tenantId"` |
| } |
| |
| // Validate implements the |
| // github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api.ParseValidator |
| // interface. |
| func (urr *UserRegistrationRequestV4) Validate(tx *sql.Tx) error { |
| var errs = []error{} |
| if urr.Role == "" { |
| errs = append(errs, errors.New("role: required and cannot be empty")) |
| } |
| |
| if urr.TenantID == 0 { |
| errs = append(errs, errors.New("tenantId: required and cannot be zero")) |
| } |
| |
| // This can only happen if an email isn't present in the request; the JSON parse handles actually |
| // invalid email addresses. |
| if urr.Email.Address.Address == "" { |
| errs = append(errs, errors.New("email: required")) |
| } |
| |
| return util.JoinErrs(errs) |
| } |
| |
| // Validate implements the |
| // github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api.ParseValidator |
| // interface. |
| func (urr *UserRegistrationRequest) Validate(tx *sql.Tx) error { |
| var errs = []error{} |
| if urr.Role == 0 { |
| errs = append(errs, errors.New("role: required and cannot be zero")) |
| } |
| |
| if urr.TenantID == 0 { |
| errs = append(errs, errors.New("tenantId: required and cannot be zero")) |
| } |
| |
| // This can only happen if an email isn't present in the request; the JSON parse handles actually |
| // invalid email addresses. |
| if urr.Email.Address.Address == "" { |
| errs = append(errs, errors.New("email: required")) |
| } |
| |
| return util.JoinErrs(errs) |
| } |