diff --git a/database/dump.sql b/database/dump.sql index 9ac19f6ec8493..e0771d8d39495 100644 --- a/database/dump.sql +++ b/database/dump.sql @@ -1,2 +1,81 @@ -- Code generated by 'make database/generate'. DO NOT EDIT. +CREATE TYPE login_type AS ENUM ( + 'built-in', + 'saml', + 'oidc' +); + +CREATE TYPE userstatus AS ENUM ( + 'active', + 'dormant', + 'decommissioned' +); + +CREATE TABLE api_keys ( + id text NOT NULL, + hashed_secret bytea NOT NULL, + user_id text NOT NULL, + application boolean NOT NULL, + name text NOT NULL, + last_used timestamp with time zone NOT NULL, + expires_at timestamp with time zone NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + login_type login_type NOT NULL, + oidc_access_token text DEFAULT ''::text NOT NULL, + oidc_refresh_token text DEFAULT ''::text NOT NULL, + oidc_id_token text DEFAULT ''::text NOT NULL, + oidc_expiry timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL, + devurl_token boolean DEFAULT false NOT NULL +); + +CREATE TABLE licenses ( + id integer NOT NULL, + license jsonb NOT NULL, + created_at timestamp with time zone NOT NULL +); + +CREATE TABLE organization_members ( + organization_id text NOT NULL, + user_id text NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + roles text[] DEFAULT '{organization-member}'::text[] NOT NULL +); + +CREATE TABLE organizations ( + id text NOT NULL, + name text NOT NULL, + description text NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + "default" boolean DEFAULT false NOT NULL, + auto_off_threshold bigint DEFAULT '28800000000000'::bigint NOT NULL, + cpu_provisioning_rate real DEFAULT 4.0 NOT NULL, + memory_provisioning_rate real DEFAULT 1.0 NOT NULL, + workspace_auto_off boolean DEFAULT false NOT NULL +); + +CREATE TABLE users ( + id text NOT NULL, + email text NOT NULL, + name text NOT NULL, + revoked boolean NOT NULL, + login_type login_type NOT NULL, + hashed_password bytea NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + temporary_password boolean DEFAULT false NOT NULL, + avatar_hash text DEFAULT ''::text NOT NULL, + ssh_key_regenerated_at timestamp with time zone DEFAULT now() NOT NULL, + username text DEFAULT ''::text NOT NULL, + dotfiles_git_uri text DEFAULT ''::text NOT NULL, + roles text[] DEFAULT '{site-member}'::text[] NOT NULL, + status userstatus DEFAULT 'active'::public.userstatus NOT NULL, + relatime timestamp with time zone DEFAULT now() NOT NULL, + gpg_key_regenerated_at timestamp with time zone DEFAULT now() NOT NULL, + _decomissioned boolean DEFAULT false NOT NULL, + shell text DEFAULT ''::text NOT NULL +); + diff --git a/database/migrations/000001_base.up.sql b/database/migrations/000001_base.up.sql index e69de29bb2d1d..91660556ea6c7 100644 --- a/database/migrations/000001_base.up.sql +++ b/database/migrations/000001_base.up.sql @@ -0,0 +1,92 @@ +-- This migration creates tables and types for v1 if they do not exist. +-- This allows v2 to operate independently of v1, but share data if it exists. +-- +-- All tables and types are stolen from: +-- https://github.com/coder/m/blob/47b6fc383347b9f9fab424d829c482defd3e1fe2/product/coder/pkg/database/dump.sql + +DO $$ BEGIN + CREATE TYPE login_type AS ENUM ( + 'built-in', + 'saml', + 'oidc' + ); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +DO $$ BEGIN + CREATE TYPE userstatus AS ENUM ( + 'active', + 'dormant', + 'decommissioned' + ); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +CREATE TABLE IF NOT EXISTS users ( + id text NOT NULL, + email text NOT NULL, + name text NOT NULL, + revoked boolean NOT NULL, + login_type login_type NOT NULL, + hashed_password bytea NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + temporary_password boolean DEFAULT false NOT NULL, + avatar_hash text DEFAULT '' :: text NOT NULL, + ssh_key_regenerated_at timestamp with time zone DEFAULT now() NOT NULL, + username text DEFAULT '' :: text NOT NULL, + dotfiles_git_uri text DEFAULT '' :: text NOT NULL, + roles text [] DEFAULT '{site-member}' :: text [] NOT NULL, + status userstatus DEFAULT 'active' :: public.userstatus NOT NULL, + relatime timestamp with time zone DEFAULT now() NOT NULL, + gpg_key_regenerated_at timestamp with time zone DEFAULT now() NOT NULL, + _decomissioned boolean DEFAULT false NOT NULL, + shell text DEFAULT '' :: text NOT NULL +); + +CREATE TABLE IF NOT EXISTS organizations ( + id text NOT NULL, + name text NOT NULL, + description text NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + "default" boolean DEFAULT false NOT NULL, + auto_off_threshold bigint DEFAULT '28800000000000' :: bigint NOT NULL, + cpu_provisioning_rate real DEFAULT 4.0 NOT NULL, + memory_provisioning_rate real DEFAULT 1.0 NOT NULL, + workspace_auto_off boolean DEFAULT false NOT NULL +); + +CREATE TABLE IF NOT EXISTS organization_members ( + organization_id text NOT NULL, + user_id text NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + roles text [] DEFAULT '{organization-member}' :: text [] NOT NULL +); + +CREATE TABLE IF NOT EXISTS api_keys ( + id text NOT NULL, + hashed_secret bytea NOT NULL, + user_id text NOT NULL, + application boolean NOT NULL, + name text NOT NULL, + last_used timestamp with time zone NOT NULL, + expires_at timestamp with time zone NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + login_type login_type NOT NULL, + oidc_access_token text DEFAULT ''::text NOT NULL, + oidc_refresh_token text DEFAULT ''::text NOT NULL, + oidc_id_token text DEFAULT ''::text NOT NULL, + oidc_expiry timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL, + devurl_token boolean DEFAULT false NOT NULL +); + +CREATE TABLE licenses ( + id integer NOT NULL, + license jsonb NOT NULL, + created_at timestamp with time zone NOT NULL +); diff --git a/database/models.go b/database/models.go index 6aa9e98b33793..c176029c54bf0 100644 --- a/database/models.go +++ b/database/models.go @@ -2,4 +2,115 @@ package database -import () +import ( + "encoding/json" + "fmt" + "time" +) + +type LoginType string + +const ( + LoginTypeBuiltIn LoginType = "built-in" + LoginTypeSaml LoginType = "saml" + LoginTypeOidc LoginType = "oidc" +) + +func (e *LoginType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = LoginType(s) + case string: + *e = LoginType(s) + default: + return fmt.Errorf("unsupported scan type for LoginType: %T", src) + } + return nil +} + +type UserStatus string + +const ( + UserstatusActive UserStatus = "active" + UserstatusDormant UserStatus = "dormant" + UserstatusDecommissioned UserStatus = "decommissioned" +) + +func (e *UserStatus) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = UserStatus(s) + case string: + *e = UserStatus(s) + default: + return fmt.Errorf("unsupported scan type for UserStatus: %T", src) + } + return nil +} + +type ApiKey struct { + ID string `db:"id" json:"id"` + HashedSecret []byte `db:"hashed_secret" json:"hashed_secret"` + UserID string `db:"user_id" json:"user_id"` + Application bool `db:"application" json:"application"` + Name string `db:"name" json:"name"` + LastUsed time.Time `db:"last_used" json:"last_used"` + ExpiresAt time.Time `db:"expires_at" json:"expires_at"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + LoginType LoginType `db:"login_type" json:"login_type"` + OidcAccessToken string `db:"oidc_access_token" json:"oidc_access_token"` + OidcRefreshToken string `db:"oidc_refresh_token" json:"oidc_refresh_token"` + OidcIDToken string `db:"oidc_id_token" json:"oidc_id_token"` + OidcExpiry time.Time `db:"oidc_expiry" json:"oidc_expiry"` + DevurlToken bool `db:"devurl_token" json:"devurl_token"` +} + +type License struct { + ID int32 `db:"id" json:"id"` + License json.RawMessage `db:"license" json:"license"` + CreatedAt time.Time `db:"created_at" json:"created_at"` +} + +type Organization struct { + ID string `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Description string `db:"description" json:"description"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + Default bool `db:"default" json:"default"` + AutoOffThreshold int64 `db:"auto_off_threshold" json:"auto_off_threshold"` + CpuProvisioningRate float32 `db:"cpu_provisioning_rate" json:"cpu_provisioning_rate"` + MemoryProvisioningRate float32 `db:"memory_provisioning_rate" json:"memory_provisioning_rate"` + WorkspaceAutoOff bool `db:"workspace_auto_off" json:"workspace_auto_off"` +} + +type OrganizationMember struct { + OrganizationID string `db:"organization_id" json:"organization_id"` + UserID string `db:"user_id" json:"user_id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + Roles []string `db:"roles" json:"roles"` +} + +type User struct { + ID string `db:"id" json:"id"` + Email string `db:"email" json:"email"` + Name string `db:"name" json:"name"` + Revoked bool `db:"revoked" json:"revoked"` + LoginType LoginType `db:"login_type" json:"login_type"` + HashedPassword []byte `db:"hashed_password" json:"hashed_password"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + TemporaryPassword bool `db:"temporary_password" json:"temporary_password"` + AvatarHash string `db:"avatar_hash" json:"avatar_hash"` + SshKeyRegeneratedAt time.Time `db:"ssh_key_regenerated_at" json:"ssh_key_regenerated_at"` + Username string `db:"username" json:"username"` + DotfilesGitUri string `db:"dotfiles_git_uri" json:"dotfiles_git_uri"` + Roles []string `db:"roles" json:"roles"` + Status UserStatus `db:"status" json:"status"` + Relatime time.Time `db:"relatime" json:"relatime"` + GpgKeyRegeneratedAt time.Time `db:"gpg_key_regenerated_at" json:"gpg_key_regenerated_at"` + Decomissioned bool `db:"_decomissioned" json:"_decomissioned"` + Shell string `db:"shell" json:"shell"` +} diff --git a/database/sqlc.yaml b/database/sqlc.yaml index 44a88f6aac9e7..006cf286b1d63 100644 --- a/database/sqlc.yaml +++ b/database/sqlc.yaml @@ -18,3 +18,5 @@ packages: overrides: - db_type: citext go_type: string +rename: + userstatus: UserStatus