Skip to content

Commit

Permalink
add user grants
Browse files Browse the repository at this point in the history
  • Loading branch information
0xch4z committed Feb 4, 2021
1 parent 75d3a38 commit 959a973
Show file tree
Hide file tree
Showing 5 changed files with 325 additions and 0 deletions.
99 changes: 99 additions & 0 deletions account_user_grants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package linodego

import (
"context"
"encoding/json"
)

type GrantPermissionLevel string

const (
AccessLevelReadOnly GrantPermissionLevel = "read_only"
AccessLevelReadWrite GrantPermissionLevel = "read_write"
)

type GlobalUserGrants struct {
AccountAccess GrantPermissionLevel `json:"account_access"`
AddDomains bool `json:"add_domains"`
AddImages bool `json:"add_images"`
AddLinodes bool `json:"add_linodes"`
AddLongview bool `json:"add_longview"`
AddNodeBalancers bool `json:"add_nodebalancers"`
AddStackScripts bool `json:"add_stackscripts"`
AddVolumes bool `json:"add_volumes"`
CancelAccount bool `json:"cancel_account"`
LongviewSubscription bool `json:"longview_subscription"`
}

type EntityUserGrant struct {
ID int `json:"id"`
Permissions GrantPermissionLevel `json:"permissions"`
}

type GrantedEntity struct {
ID int `json:"id"`
Label string `json:"label"`
Permissions GrantPermissionLevel `json:"permissions"`
}

type UserGrants struct {
Domain []GrantedEntity `json:"domain"`
Image []GrantedEntity `json:"image"`
Linode []GrantedEntity `json:"linode"`
Longview []GrantedEntity `json:"longview"`
NodeBalancer []GrantedEntity `json:"nodebalancer"`
StackScript []GrantedEntity `json:"stackscript"`
Volume []GrantedEntity `json:"volume"`

Global GlobalUserGrants `json:"global"`
}

type UserGrantsUpdateOptions struct {
Domain []EntityUserGrant `json:"domain,omitempty"`
Image []EntityUserGrant `json:"image,omitempty"`
Linode []EntityUserGrant `json:"linode,omitempty"`
Longview []EntityUserGrant `json:"longview,omitempty"`
NodeBalancer []EntityUserGrant `json:"nodebalancer,omitempty"`
StackScript []EntityUserGrant `json:"stackscript,omitempty"`
Volume []EntityUserGrant `json:"volume,omitempty"`

Global GlobalUserGrants `json:"global"`
}

func (c *Client) GetUserGrants(ctx context.Context, username string) (*UserGrants, error) {
e, err := c.UserGrants.endpointWithParams(username)
if err != nil {
return nil, err
}

r, err := coupleAPIErrors(c.R(ctx).SetResult(&UserGrants{}).Get(e))
if err != nil {
return nil, err
}

return r.Result().(*UserGrants), nil
}

func (c *Client) UpdateUserGrants(ctx context.Context, username string, updateOpts UserGrantsUpdateOptions) (*UserGrants, error) {
var body string

e, err := c.UserGrants.endpointWithParams(username)
if err != nil {
return nil, err
}

req := c.R(ctx).SetResult(&UserGrants{})

if bodyData, err := json.Marshal(updateOpts); err == nil {
body = string(bodyData)
} else {
return nil, NewError(err)
}

r, err := coupleAPIErrors(req.SetBody(body).Put(e))
if err != nil {
return nil, err
}

return r.Result().(*UserGrants), nil
}
3 changes: 3 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ type Client struct {
Token *Resource
Tokens *Resource
Types *Resource
UserGrants *Resource
Users *Resource
VLANs *Resource
Volumes *Resource
Expand Down Expand Up @@ -327,6 +328,7 @@ func addResources(client *Client) {
ticketsName: NewResource(client, ticketsName, ticketsEndpoint, false, Ticket{}, TicketsPagedResponse{}),
tokensName: NewResource(client, tokensName, tokensEndpoint, false, Token{}, TokensPagedResponse{}),
typesName: NewResource(client, typesName, typesEndpoint, false, LinodeType{}, LinodeTypesPagedResponse{}),
userGrantsName: NewResource(client, typesName, userGrantsEndpoint, true, UserGrants{}, nil),
usersName: NewResource(client, usersName, usersEndpoint, false, User{}, UsersPagedResponse{}),
vlansName: NewResource(client, vlansName, vlansEndpoint, false, VLAN{}, VLANsPagedResponse{}),
volumesName: NewResource(client, volumesName, volumesEndpoint, false, Volume{}, VolumesPagedResponse{}),
Expand Down Expand Up @@ -380,6 +382,7 @@ func addResources(client *Client) {
client.Tickets = resources[ticketsName]
client.Tokens = resources[tokensName]
client.Types = resources[typesName]
client.UserGrants = resources[userGrantsName]
client.Users = resources[usersName]
client.VLANs = resources[vlansName]
client.Volumes = resources[volumesName]
Expand Down
2 changes: 2 additions & 0 deletions resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const (
ticketsName = "tickets"
tokensName = "tokens"
typesName = "types"
userGrantsName = "usergrants"
usersName = "users"
volumesName = "volumes"
vlansName = "vlans"
Expand Down Expand Up @@ -116,6 +117,7 @@ const (
ticketsEndpoint = "support/tickets"
tokensEndpoint = "profile/tokens"
typesEndpoint = "linode/types"
userGrantsEndpoint = "account/users/{{ .ID }}/grants"
usersEndpoint = "account/users"
vlansEndpoint = "networking/vlans"
volumesEndpoint = "volumes"
Expand Down
55 changes: 55 additions & 0 deletions test/integration/account_user_grants_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package integration

import (
"context"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/linode/linodego"
)

func TestUpdateUserGrants(t *testing.T) {
username := usernamePrefix + "updateusergrants"

client, _, teardown := setupUser(t, []userModifier{
func(createOpts *linodego.UserCreateOptions) {
createOpts.Username = username
createOpts.Email = usernamePrefix + "[email protected]"
createOpts.Restricted = true
},
}, "fixtures/TestUpdateUserGrants")
defer teardown()

globalGrants := linodego.GlobalUserGrants{
AccountAccess: linodego.AccessLevelReadOnly,
AddDomains: false,
AddImages: true,
AddLinodes: false,
AddLongview: true,
AddNodeBalancers: false,
AddStackScripts: true,
AddVolumes: true,
CancelAccount: false,
}

expectedUserGrants := linodego.UserGrants{
Global: globalGrants,
Domain: []linodego.GrantedEntity{},
Image: []linodego.GrantedEntity{},
Linode: []linodego.GrantedEntity{},
Longview: []linodego.GrantedEntity{},
NodeBalancer: []linodego.GrantedEntity{},
StackScript: []linodego.GrantedEntity{},
Volume: []linodego.GrantedEntity{},
}
grants, err := client.UpdateUserGrants(context.TODO(), username, linodego.UserGrantsUpdateOptions{
Global: globalGrants,
})
if err != nil {
t.Fatalf("failed to get user grants: %s", err)
}

if !cmp.Equal(grants, &expectedUserGrants) {
t.Errorf("expected rules to match test rules, but got diff: %s", cmp.Diff(grants, &expectedUserGrants))
}
}
166 changes: 166 additions & 0 deletions test/integration/fixtures/TestUpdateUserGrants.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
version: 1
interactions:
- request:
body: '{"username":"linodegotest-updateusergrants","email":"[email protected]","restricted":true}'
form: {}
headers:
Accept:
- application/json
Content-Type:
- application/json
User-Agent:
- linodego https://github.com/linode/linodego
url: https://api.linode.com/v4beta/account/users
method: POST
response:
body: '{"username": "linodegotest-updateusergrants", "email": "[email protected]", "restricted": true, "ssh_keys": [], "tfa_enabled": false}'
headers:
Access-Control-Allow-Credentials:
- "true"
Access-Control-Allow-Headers:
- Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter
Access-Control-Allow-Methods:
- HEAD, GET, OPTIONS, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Access-Control-Expose-Headers:
- X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status
Cache-Control:
- private, max-age=60, s-maxage=60
Content-Length:
- "157"
Content-Security-Policy:
- default-src 'none'
Content-Type:
- application/json
Server:
- nginx
Strict-Transport-Security:
- max-age=31536000
Vary:
- Authorization, X-Filter
X-Accepted-Oauth-Scopes:
- account:read_write
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
- DENY
X-Oauth-Scopes:
- '*'
X-Ratelimit-Limit:
- "800"
X-Xss-Protection:
- 1; mode=block
status: 200 OK
code: 200
duration: ""
- request:
body: '{"global":{"account_access":"read_only","add_domains":false,"add_images":true,"add_linodes":false,"add_longview":true,"add_nodebalancers":false,"add_stackscripts":true,"add_volumes":true,"cancel_account":false,"longview_subscription":false}}'
form: {}
headers:
Accept:
- application/json
Content-Type:
- application/json
User-Agent:
- linodego https://github.com/linode/linodego
url: https://api.linode.com/v4beta/account/users/linodegotest-updateusergrants/grants
method: PUT
response:
body: '{"linode": [], "nodebalancer": [], "domain": [], "stackscript": [], "longview": [], "image": [], "volume": [], "global": {"add_domains": false, "add_linodes": false, "add_longview": true, "longview_subscription": false, "add_stackscripts": true, "add_nodebalancers": false, "add_images": true, "add_volumes": true, "account_access": "read_only", "cancel_account": false}}'
headers:
Access-Control-Allow-Credentials:
- "true"
Access-Control-Allow-Headers:
- Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter
Access-Control-Allow-Methods:
- HEAD, GET, OPTIONS, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Access-Control-Expose-Headers:
- X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status
Cache-Control:
- private, max-age=60, s-maxage=60
Content-Security-Policy:
- default-src 'none'
Content-Type:
- application/json
Server:
- nginx
Strict-Transport-Security:
- max-age=31536000
Vary:
- Authorization, X-Filter
X-Accepted-Oauth-Scopes:
- account:read_write
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
- DENY
X-Oauth-Scopes:
- '*'
X-Ratelimit-Limit:
- "800"
X-Xss-Protection:
- 1; mode=block
status: 200 OK
code: 200
duration: ""
- request:
body: ""
form: {}
headers:
Accept:
- application/json
Content-Type:
- application/json
User-Agent:
- linodego https://github.com/linode/linodego
url: https://api.linode.com/v4beta/account/users/linodegotest-updateusergrants
method: DELETE
response:
body: '{}'
headers:
Access-Control-Allow-Credentials:
- "true"
Access-Control-Allow-Headers:
- Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter
Access-Control-Allow-Methods:
- HEAD, GET, OPTIONS, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Access-Control-Expose-Headers:
- X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status
Cache-Control:
- private, max-age=60, s-maxage=60
Content-Length:
- "2"
Content-Security-Policy:
- default-src 'none'
Content-Type:
- application/json
Server:
- nginx
Strict-Transport-Security:
- max-age=31536000
Vary:
- Authorization, X-Filter
X-Accepted-Oauth-Scopes:
- account:read_write
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
- DENY
X-Oauth-Scopes:
- '*'
X-Ratelimit-Limit:
- "800"
X-Xss-Protection:
- 1; mode=block
status: 200 OK
code: 200
duration: ""

0 comments on commit 959a973

Please sign in to comment.