Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions profile_apps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package linodego

import (
"context"
"encoding/json"
"time"

"github.com/linode/linodego/internal/parseabletime"
)

// ProfileApp represents a ProfileApp object
type ProfileApp struct {
// When this app was authorized.
Created *time.Time `json:"-"`

// When the app's access to your account expires.
Expiry *time.Time `json:"-"`

// This authorization's ID, used for revoking access.
ID int `json:"id"`

// The name of the application you've authorized.
Label string `json:"label"`

// The OAuth scopes this app was authorized with.
Scopes string `json:"scopes"`

// The URL at which this app's thumbnail may be accessed.
ThumbnailURL string `json:"thumbnail_url"`

// The website where you can get more information about this app.
Website string `json:"website"`
}

// UnmarshalJSON implements the json.Unmarshaler interface
func (pa *ProfileApp) UnmarshalJSON(b []byte) error {
type Mask ProfileApp

l := struct {
*Mask
Created *parseabletime.ParseableTime `json:"created"`
Expiry *parseabletime.ParseableTime `json:"expiry"`
}{
Mask: (*Mask)(pa),
}

if err := json.Unmarshal(b, &l); err != nil {
return err
}

pa.Created = (*time.Time)(l.Created)
pa.Expiry = (*time.Time)(l.Expiry)

return nil
}

// GetProfileApp returns the ProfileApp with the provided id
func (c *Client) GetProfileApp(ctx context.Context, appID int) (*ProfileApp, error) {
e := formatAPIPath("profile/apps/%d", appID)
return doGETRequest[ProfileApp](ctx, c, e)
}

// ListProfileApps lists ProfileApps that have access to the Account
func (c *Client) ListProfileApps(ctx context.Context, opts *ListOptions) ([]ProfileApp, error) {
return getPaginatedResults[ProfileApp](ctx, c, "profile/apps", opts)
}

// DeleteProfileApp revokes the given ProfileApp's access to the account
func (c *Client) DeleteProfileApp(ctx context.Context, appID int) error {
e := formatAPIPath("profile/apps/%d", appID)
err := doDELETERequest(ctx, c, e)
return err
}
72 changes: 72 additions & 0 deletions profile_devices.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package linodego

import (
"context"
"encoding/json"
"time"

"github.com/linode/linodego/internal/parseabletime"
)

// ProfileDevice represents a ProfileDevice object
type ProfileDevice struct {
// When this Remember Me session was started.
Created *time.Time `json:"-"`

// When this TrustedDevice session expires. Sessions typically last 30 days.
Expiry *time.Time `json:"-"`

// The unique ID for this TrustedDevice.
ID int `json:"id"`

// he last time this TrustedDevice was successfully used to authenticate to login.linode.com
LastAuthenticated *time.Time `json:"-"`

// The last IP Address to successfully authenticate with this TrustedDevice.
LastRemoteAddr string `json:"last_remote_addr"`

// The User Agent of the browser that created this TrustedDevice session.
UserAgent string `json:"user_agent"`
}

// UnmarshalJSON implements the json.Unmarshaler interface
func (pd *ProfileDevice) UnmarshalJSON(b []byte) error {
type Mask ProfileDevice

l := struct {
*Mask
Created *parseabletime.ParseableTime `json:"created"`
Expiry *parseabletime.ParseableTime `json:"expiry"`
LastAuthenticated *parseabletime.ParseableTime `json:"last_authenticated"`
}{
Mask: (*Mask)(pd),
}

if err := json.Unmarshal(b, &l); err != nil {
return err
}

pd.Created = (*time.Time)(l.Created)
pd.Expiry = (*time.Time)(l.Expiry)
pd.LastAuthenticated = (*time.Time)(l.LastAuthenticated)

return nil
}

// GetProfileDevice returns the ProfileDevice with the provided id
func (c *Client) GetProfileDevice(ctx context.Context, deviceID int) (*ProfileDevice, error) {
e := formatAPIPath("profile/devices/%d", deviceID)
return doGETRequest[ProfileDevice](ctx, c, e)
}

// ListProfileDevices lists ProfileDevices for the User
func (c *Client) ListProfileDevices(ctx context.Context, opts *ListOptions) ([]ProfileDevice, error) {
return getPaginatedResults[ProfileDevice](ctx, c, "profile/devices", opts)
}

// DeleteProfileDevice revokes the given ProfileDevice's status as a trusted device
func (c *Client) DeleteProfileDevice(ctx context.Context, deviceID int) error {
e := formatAPIPath("profile/devices/%d", deviceID)
err := doDELETERequest(ctx, c, e)
return err
}
32 changes: 32 additions & 0 deletions profile_preferences.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package linodego

import (
"context"
"encoding/json"
)

// ProfilePreferences represents the user's preferences.
// The user preferences endpoints allow consumers of the API to store arbitrary JSON data,
// such as a user's font size preference or preferred display name.
type ProfilePreferences map[string]interface{}

// UnmarshalJSON implements the json.Unmarshaler interface
func (p *ProfilePreferences) UnmarshalJSON(b []byte) error {
var data map[string]interface{}
if err := json.Unmarshal(b, &data); err != nil {
return err
}

*p = data
return nil
}

// GetProfilePreferences retrieves the user preferences for the current User
func (c *Client) GetProfilePreferences(ctx context.Context) (*ProfilePreferences, error) {
return doGETRequest[ProfilePreferences](ctx, c, "profile/preferences")
}

// UpdateProfilePreferences updates the user's preferences with the provided data
func (c *Client) UpdateProfilePreferences(ctx context.Context, opts ProfilePreferences) (*ProfilePreferences, error) {
return doPUTRequest[ProfilePreferences](ctx, c, "profile/preferences", opts)
}
9 changes: 9 additions & 0 deletions test/unit/fixtures/profile_apps_get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"created": "2018-01-01T00:01:01",
"expiry": "2018-01-15T00:01:01",
"id": 123,
"label": "example-app",
"scopes": "linodes:read_only",
"thumbnail_url": null,
"website": "example.org"
}
16 changes: 16 additions & 0 deletions test/unit/fixtures/profile_apps_list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"data": [
{
"created": "2018-01-01T00:01:01",
"expiry": "2018-01-15T00:01:01",
"id": 123,
"label": "example-app",
"scopes": "linodes:read_only",
"thumbnail_url": null,
"website": "example.org"
}
],
"page": 1,
"pages": 1,
"results": 1
}
8 changes: 8 additions & 0 deletions test/unit/fixtures/profile_devices_get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"created": "2018-01-01T01:01:01",
"expiry": "2018-01-31T01:01:01",
"id": 123,
"last_authenticated": "2018-01-05T12:57:12",
"last_remote_addr": "203.0.113.1",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Vivaldi/2.1.1337.36"
}
15 changes: 15 additions & 0 deletions test/unit/fixtures/profile_devices_list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"data": [
{
"created": "2018-01-01T01:01:01",
"expiry": "2018-01-31T01:01:01",
"id": 123,
"last_authenticated": "2018-01-05T12:57:12",
"last_remote_addr": "203.0.113.1",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Vivaldi/2.1.1337.36"
}
],
"page": 1,
"pages": 1,
"results": 1
}
4 changes: 4 additions & 0 deletions test/unit/fixtures/profile_preferences_get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"key1": "value1",
"key2": "value2"
}
4 changes: 4 additions & 0 deletions test/unit/fixtures/profile_preferences_update.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"key1": "value1_new",
"key2": "value2_new"
}
59 changes: 59 additions & 0 deletions test/unit/profile_apps_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package unit

import (
"context"
"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/assert"
"testing"
)

func TestProfileApps_Get(t *testing.T) {
fixtureData, err := fixtures.GetFixture("profile_apps_get")
assert.NoError(t, err)

var base ClientBaseCase
base.SetUp(t)
defer base.TearDown(t)

base.MockGet("profile/apps/123", fixtureData)

app, err := base.Client.GetProfileApp(context.Background(), 123)
assert.NoError(t, err)

assert.Equal(t, 123, app.ID)
assert.Equal(t, "example-app", app.Label)
assert.Equal(t, "linodes:read_only", app.Scopes)
assert.Equal(t, "example.org", app.Website)
}

func TestProfileApps_List(t *testing.T) {
fixtureData, err := fixtures.GetFixture("profile_apps_list")
assert.NoError(t, err)

var base ClientBaseCase
base.SetUp(t)
defer base.TearDown(t)

base.MockGet("profile/apps", fixtureData)

apps, err := base.Client.ListProfileApps(context.Background(), nil)
assert.NoError(t, err)

assert.Equal(t, 1, len(apps))
app := apps[0]

assert.Equal(t, 123, app.ID)
assert.Equal(t, "example-app", app.Label)
assert.Equal(t, "linodes:read_only", app.Scopes)
assert.Equal(t, "example.org", app.Website)
}

func TestProfileApps_Delete(t *testing.T) {
client := createMockClient(t)

httpmock.RegisterRegexpResponder("DELETE", mockRequestURL(t, "profile/apps/123"), httpmock.NewStringResponder(200, "{}"))

if err := client.DeleteProfileApp(context.Background(), 123); err != nil {
t.Fatal(err)
}
}
57 changes: 57 additions & 0 deletions test/unit/profile_devices_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package unit

import (
"context"
"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/assert"
"testing"
)

func TestProfileDevices_Get(t *testing.T) {
fixtureData, err := fixtures.GetFixture("profile_devices_get")
assert.NoError(t, err)

var base ClientBaseCase
base.SetUp(t)
defer base.TearDown(t)

base.MockGet("profile/devices/123", fixtureData)

device, err := base.Client.GetProfileDevice(context.Background(), 123)
assert.NoError(t, err)

assert.Equal(t, 123, device.ID)
assert.Equal(t, "203.0.113.1", device.LastRemoteAddr)
assert.Equal(t, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Vivaldi/2.1.1337.36", device.UserAgent)
}

func TestProfileDevices_List(t *testing.T) {
fixtureData, err := fixtures.GetFixture("profile_devices_list")
assert.NoError(t, err)

var base ClientBaseCase
base.SetUp(t)
defer base.TearDown(t)

base.MockGet("profile/devices", fixtureData)

devices, err := base.Client.ListProfileDevices(context.Background(), nil)
assert.NoError(t, err)

assert.Equal(t, 1, len(devices))
device := devices[0]

assert.Equal(t, 123, device.ID)
assert.Equal(t, "203.0.113.1", device.LastRemoteAddr)
assert.Equal(t, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Vivaldi/2.1.1337.36", device.UserAgent)
}

func TestProfileDevices_Delete(t *testing.T) {
client := createMockClient(t)

httpmock.RegisterRegexpResponder("DELETE", mockRequestURL(t, "profile/devices/123"), httpmock.NewStringResponder(200, "{}"))

if err := client.DeleteProfileDevice(context.Background(), 123); err != nil {
t.Fatal(err)
}
}
Loading