// Package db2sdk provides common conversion routines from database types to codersdk types package db2sdk import ( "encoding/json" "strings" "github.com/google/uuid" "golang.org/x/exp/slices" "golang.org/x/xerrors" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/parameter" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/provisionersdk/proto" ) func WorkspaceBuildParameters(params []database.WorkspaceBuildParameter) []codersdk.WorkspaceBuildParameter { out := make([]codersdk.WorkspaceBuildParameter, len(params)) for i, p := range params { out[i] = WorkspaceBuildParameter(p) } return out } func WorkspaceBuildParameter(p database.WorkspaceBuildParameter) codersdk.WorkspaceBuildParameter { return codersdk.WorkspaceBuildParameter{ Name: p.Name, Value: p.Value, } } func TemplateVersionParameters(params []database.TemplateVersionParameter) ([]codersdk.TemplateVersionParameter, error) { out := make([]codersdk.TemplateVersionParameter, len(params)) var err error for i, p := range params { out[i], err = TemplateVersionParameter(p) if err != nil { return nil, xerrors.Errorf("convert template version parameter %q: %w", p.Name, err) } } return out, nil } func TemplateVersionParameter(param database.TemplateVersionParameter) (codersdk.TemplateVersionParameter, error) { options, err := templateVersionParameterOptions(param.Options) if err != nil { return codersdk.TemplateVersionParameter{}, err } descriptionPlaintext, err := parameter.Plaintext(param.Description) if err != nil { return codersdk.TemplateVersionParameter{}, err } var validationMin *int32 if param.ValidationMin.Valid { validationMin = ¶m.ValidationMin.Int32 } var validationMax *int32 if param.ValidationMax.Valid { validationMax = ¶m.ValidationMax.Int32 } return codersdk.TemplateVersionParameter{ Name: param.Name, DisplayName: param.DisplayName, Description: param.Description, DescriptionPlaintext: descriptionPlaintext, Type: param.Type, Mutable: param.Mutable, DefaultValue: param.DefaultValue, Icon: param.Icon, Options: options, ValidationRegex: param.ValidationRegex, ValidationMin: validationMin, ValidationMax: validationMax, ValidationError: param.ValidationError, ValidationMonotonic: codersdk.ValidationMonotonicOrder(param.ValidationMonotonic), Required: param.Required, Ephemeral: param.Ephemeral, }, nil } func User(user database.User, organizationIDs []uuid.UUID) codersdk.User { convertedUser := codersdk.User{ ID: user.ID, Email: user.Email, CreatedAt: user.CreatedAt, LastSeenAt: user.LastSeenAt, Username: user.Username, Status: codersdk.UserStatus(user.Status), OrganizationIDs: organizationIDs, Roles: make([]codersdk.Role, 0, len(user.RBACRoles)), AvatarURL: user.AvatarURL.String, LoginType: codersdk.LoginType(user.LoginType), } for _, roleName := range user.RBACRoles { rbacRole, _ := rbac.RoleByName(roleName) convertedUser.Roles = append(convertedUser.Roles, Role(rbacRole)) } return convertedUser } func Role(role rbac.Role) codersdk.Role { return codersdk.Role{ DisplayName: role.DisplayName, Name: role.Name, } } func TemplateInsightsParameters(parameterRows []database.GetTemplateParameterInsightsRow) ([]codersdk.TemplateParameterUsage, error) { // Use a stable sort, similarly to how we would sort in the query, note that // we don't sort in the query because order varies depending on the table // collation. // // ORDER BY utp.name, utp.type, utp.display_name, utp.description, utp.options, wbp.value slices.SortFunc(parameterRows, func(a, b database.GetTemplateParameterInsightsRow) int { if a.Name != b.Name { return strings.Compare(a.Name, b.Name) } if a.Type != b.Type { return strings.Compare(a.Type, b.Type) } if a.DisplayName != b.DisplayName { return strings.Compare(a.DisplayName, b.DisplayName) } if a.Description != b.Description { return strings.Compare(a.Description, b.Description) } if string(a.Options) != string(b.Options) { return strings.Compare(string(a.Options), string(b.Options)) } return strings.Compare(a.Value, b.Value) }) parametersUsage := []codersdk.TemplateParameterUsage{} indexByNum := make(map[int64]int) for _, param := range parameterRows { if _, ok := indexByNum[param.Num]; !ok { var opts []codersdk.TemplateVersionParameterOption err := json.Unmarshal(param.Options, &opts) if err != nil { return nil, err } plaintextDescription, err := parameter.Plaintext(param.Description) if err != nil { return nil, err } parametersUsage = append(parametersUsage, codersdk.TemplateParameterUsage{ TemplateIDs: param.TemplateIDs, Name: param.Name, Type: param.Type, DisplayName: param.DisplayName, Description: plaintextDescription, Options: opts, }) indexByNum[param.Num] = len(parametersUsage) - 1 } i := indexByNum[param.Num] parametersUsage[i].Values = append(parametersUsage[i].Values, codersdk.TemplateParameterValue{ Value: param.Value, Count: param.Count, }) } return parametersUsage, nil } func templateVersionParameterOptions(rawOptions json.RawMessage) ([]codersdk.TemplateVersionParameterOption, error) { var protoOptions []*proto.RichParameterOption err := json.Unmarshal(rawOptions, &protoOptions) if err != nil { return nil, err } var options []codersdk.TemplateVersionParameterOption for _, option := range protoOptions { options = append(options, codersdk.TemplateVersionParameterOption{ Name: option.Name, Description: option.Description, Value: option.Value, Icon: option.Icon, }) } return options, nil }