Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Add more coder-sdk operations #169

Merged
merged 1 commit into from
Nov 3, 2020
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
9 changes: 4 additions & 5 deletions coder-sdk/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"net/http"
"time"

"cdr.dev/coder-cli/internal/x/xjson"
"golang.org/x/xerrors"
"nhooyr.io/websocket"
"nhooyr.io/websocket/wsjson"
Expand All @@ -31,14 +30,14 @@ type Environment struct {
UpdatedAt time.Time `json:"updated_at" table:"-"`
LastOpenedAt time.Time `json:"last_opened_at" table:"-"`
LastConnectionAt time.Time `json:"last_connection_at" table:"-"`
AutoOffThreshold xjson.MSDuration `json:"auto_off_threshold" table:"-"`
AutoOffThreshold Duration `json:"auto_off_threshold" table:"-"`
}

// RebuildMessage defines the message shown when an Environment requires a rebuild for it can be accessed.
type RebuildMessage struct {
Text string `json:"text"`
Required bool `json:"required"`
AutoOffThreshold xjson.MSDuration `json:"auto_off_threshold" table:"-"`
Text string `json:"text"`
Required bool `json:"required"`
AutoOffThreshold Duration `json:"auto_off_threshold"`
}

// EnvironmentStat represents the state of an environment
Expand Down
9 changes: 6 additions & 3 deletions coder-sdk/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ var ErrNotFound = xerrors.Errorf("resource not found")

// APIError is the expected payload format for our errors.
type APIError struct {
Err struct {
Msg string `json:"msg"`
} `json:"error"`
Err APIErrorMsg `json:"error"`
}

// APIErrorMsg contains the rich error information returned by API errors.
type APIErrorMsg struct {
Msg string `json:"msg"`
}

// HTTPError represents an error from the Coder API.
Expand Down
6 changes: 3 additions & 3 deletions coder-sdk/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ type NewRegistryRequest struct {
Password string `json:"password"`
}

// ImportImageRequest is used to import new images and registries into Coder
type ImportImageRequest struct {
// ImportImageReq is used to import new images and registries into Coder
type ImportImageReq struct {
RegistryID *string `json:"registry_id"` // Used to import images to existing registries.
NewRegistry *NewRegistryRequest `json:"new_registry"` // Used when adding a new registry.
Repository string `json:"repository"` // Refers to the image. Ex: "codercom/ubuntu".
Expand All @@ -40,7 +40,7 @@ type ImportImageRequest struct {
}

// ImportImage creates a new image and optionally a new registry
func (c Client) ImportImage(ctx context.Context, orgID string, req ImportImageRequest) (*Image, error) {
func (c Client) ImportImage(ctx context.Context, orgID string, req ImportImageReq) (*Image, error) {
var img Image
if err := c.requestBody(ctx, http.MethodPost, "/api/orgs/"+orgID+"/images", req, &img); err != nil {
return nil, err
Expand Down
59 changes: 48 additions & 11 deletions coder-sdk/org.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,15 @@ type Organization struct {
// OrganizationUser user wraps the basic User type and adds data specific to the user's membership of an organization
type OrganizationUser struct {
User
OrganizationRoles []OrganizationRole `json:"organization_roles"`
RolesUpdatedAt time.Time `json:"roles_updated_at"`
OrganizationRoles []Role `json:"organization_roles"`
RolesUpdatedAt time.Time `json:"roles_updated_at"`
}

// OrganizationRole defines an organization OrganizationRole
type OrganizationRole string

// The OrganizationRole enum values
// Organization Roles
const (
RoleOrgMember OrganizationRole = "organization-member"
RoleOrgAdmin OrganizationRole = "organization-admin"
RoleOrgManager OrganizationRole = "organization-manager"
RoleOrgMember Role = "organization-member"
RoleOrgAdmin Role = "organization-admin"
RoleOrgManager Role = "organization-manager"
)

// Organizations gets all Organizations
Expand All @@ -39,11 +36,51 @@ func (c Client) Organizations(ctx context.Context) ([]Organization, error) {
return orgs, nil
}

// OrgMembers get all members of the given organization
func (c Client) OrgMembers(ctx context.Context, orgID string) ([]OrganizationUser, error) {
func (c Client) OrganizationByID(ctx context.Context, orgID string) (*Organization, error) {
var org Organization
err := c.requestBody(ctx, http.MethodGet, "/api/orgs/"+orgID, nil, &org)
if err != nil {
return nil, err
}
return &org, nil
}

// OrganizationMembers get all members of the given organization
func (c Client) OrganizationMembers(ctx context.Context, orgID string) ([]OrganizationUser, error) {
var members []OrganizationUser
if err := c.requestBody(ctx, http.MethodGet, "/api/orgs/"+orgID+"/members", nil, &members); err != nil {
return nil, err
}
return members, nil
}

type UpdateOrganizationReq struct {
Name *string `json:"name"`
Description *string `json:"description"`
Default *bool `json:"default"`
AutoOffThreshold *Duration `json:"auto_off_threshold"`
CPUProvisioningRate *float32 `json:"cpu_provisioning_rate"`
MemoryProvisioningRate *float32 `json:"memory_provisioning_rate"`
}

func (c Client) UpdateOrganization(ctx context.Context, orgID string, req UpdateOrganizationReq) error {
return c.requestBody(ctx, http.MethodPatch, "/api/orgs/"+orgID, req, nil)
}

type CreateOrganizationReq struct {
Name string `json:"name"`
Description string `json:"description"`
Default bool `json:"default"`
ResourceNamespace string `json:"resource_namespace"`
AutoOffThreshold Duration `json:"auto_off_threshold"`
CPUProvisioningRate float32 `json:"cpu_provisioning_rate"`
MemoryProvisioningRate float32 `json:"memory_provisioning_rate"`
}

func (c Client) CreateOrganization(ctx context.Context, req CreateOrganizationReq) error {
return c.requestBody(ctx, http.MethodPost, "/api/orgs", req, nil)
}

func (c Client) DeleteOrganization(ctx context.Context, orgID string) error {
return c.requestBody(ctx, http.MethodDelete, "/api/orgs/"+orgID, nil, nil)
}
67 changes: 61 additions & 6 deletions coder-sdk/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,38 @@ import (

// User describes a Coder user account.
type User struct {
ID string `json:"id" table:"-"`
Email string `json:"email" table:"Email"`
Username string `json:"username" table:"Username"`
Name string `json:"name" table:"Name"`
CreatedAt time.Time `json:"created_at" table:"CreatedAt"`
UpdatedAt time.Time `json:"updated_at" table:"-"`
ID string `json:"id" table:"-"`
Email string `json:"email" table:"Email"`
Username string `json:"username" table:"Username"`
Name string `json:"name" table:"Name"`
Roles []Role `json:"roles" table:"-"`
TemporaryPassword bool `json:"temporary_password" table:"-"`
LoginType string `json:"login_type" table:"-"`
KeyRegeneratedAt time.Time `json:"key_regenerated_at" table:"-"`
CreatedAt time.Time `json:"created_at" table:"CreatedAt"`
UpdatedAt time.Time `json:"updated_at" table:"-"`
}

type Role string

type Roles []Role

// Site Roles
const (
SiteAdmin Role = "site-admin"
SiteAuditor Role = "site-auditor"
SiteManager Role = "site-manager"
SiteMember Role = "site-member"
)

type LoginType string

const (
LoginTypeBuiltIn LoginType = "built-in"
LoginTypeSAML LoginType = "saml"
LoginTypeOIDC LoginType = "oidc"
)

// Me gets the details of the authenticated user.
func (c Client) Me(ctx context.Context) (*User, error) {
return c.UserByID(ctx, Me)
Expand Down Expand Up @@ -70,3 +94,34 @@ func (c Client) UserByEmail(ctx context.Context, email string) (*User, error) {
}
return nil, ErrNotFound
}

// UpdateUserReq defines a modification to the user, updating the
// value of all non-nil values.
type UpdateUserReq struct {
// TODO(@cmoog) add update password option
Revoked *bool `json:"revoked,omitempty"`
Roles *Roles `json:"roles,omitempty"`
LoginType *LoginType `json:"login_type,omitempty"`
Name *string `json:"name,omitempty"`
Username *string `json:"username,omitempty"`
Email *string `json:"email,omitempty"`
DotfilesGitURL *string `json:"dotfiles_git_uri,omitempty"`
}

func (c Client) UpdateUser(ctx context.Context, userID string, req UpdateUserReq) error {
return c.requestBody(ctx, http.MethodPatch, "/api/users/"+userID, req, nil)
}

type CreateUserReq struct {
Name string `json:"name"`
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
TemporaryPassword bool `json:"temporary_password"`
LoginType LoginType `json:"login_type"`
OrganizationsIDs []string `json:"organizations"`
}

func (c Client) CreateUser(ctx context.Context, req CreateUserReq) error {
return c.requestBody(ctx, http.MethodPost, "/api/users", req, nil)
}
35 changes: 35 additions & 0 deletions coder-sdk/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package coder

import (
"encoding/json"
"strconv"
"time"
)

func String(s string) *string {
return &s
}

// Duration is a time.Duration wrapper that marshals to millisecond precision.
// While it looses precision, most javascript applications expect durations to be in milliseconds.
type Duration time.Duration

// MarshalJSON marshals the duration to millisecond precision.
func (d Duration) MarshalJSON() ([]byte, error) {
du := time.Duration(d)
return json.Marshal(du.Milliseconds())
}

// UnmarshalJSON unmarshals a millisecond-precision integer to
// a time.Duration.
func (d *Duration) UnmarshalJSON(b []byte) error {
i, err := strconv.ParseInt(string(b), 10, 64)
if err != nil {
return err
}

*d = Duration(time.Duration(i) * time.Millisecond)
return nil
}

func (d Duration) String() string { return time.Duration(d).String() }
31 changes: 0 additions & 31 deletions internal/x/xjson/duration.go

This file was deleted.