Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dashboard): library and database types #339

Closed
wants to merge 13 commits into from
3 changes: 3 additions & 0 deletions constants/limit.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const (
// FavoritesMaxSize defines the maximum size in characters for user favorites.
FavoritesMaxSize = 5000

// DashboardAdminMaxSize defines the maximum size in characters for dashboard admins.
DashboardAdminMaxSize = 5000

// RunningBuildIDsMaxSize defines the maximum size in characters for worker RunningBuildIDs.
RunningBuildIDsMaxSize = 500

Expand Down
3 changes: 3 additions & 0 deletions constants/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const (
// TableBuildExecutable defines the table type for the database build_executables table.
TableBuildExecutable = "build_executables"

// TableDashboard defines the table type for the database dashboards table.
TableDashboard = "dashboards"

// TableDeployment defines the table type for the database deployments table.
TableDeployment = "deployments"

Expand Down
180 changes: 180 additions & 0 deletions database/dashboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// SPDX-License-Identifier: Apache-2.0

package database

import (
"database/sql"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"

"github.com/go-vela/types/constants"
"github.com/go-vela/types/library"
"github.com/google/uuid"
"github.com/lib/pq"
)

var (
// ErrEmptyDashName defines the error type when a
// User type has an empty Name field provided.
ErrEmptyDashName = errors.New("empty dashboard name provided")

// ErrExceededAdminLimit defines the error type when a
// User type has Admins field provided that exceeds the database limit.
ErrExceededAdminLimit = errors.New("exceeded admins limit")
)

// Dashboard is the database representation of a user.
type Dashboard struct {
ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4()"`
Name sql.NullString `sql:"name"`
CreatedAt sql.NullInt64 `sql:"created_at"`
CreatedBy sql.NullString `sql:"created_by"`
UpdatedAt sql.NullInt64 `sql:"updated_at"`
UpdatedBy sql.NullString `sql:"updated_by"`
Admins pq.StringArray `sql:"admins" gorm:"type:varchar(5000)"`
Repos DashReposJSON
}

type DashReposJSON []*library.DashboardRepo

// Value - Implementation of valuer for database/sql for DashReposJSON.
func (r DashReposJSON) Value() (driver.Value, error) {
valueString, err := json.Marshal(r)
return string(valueString), err
}

// Scan - Implement the database/sql scanner interface for DashReposJSON.
func (r *DashReposJSON) Scan(value interface{}) error {
switch v := value.(type) {
case []byte:
return json.Unmarshal(v, &r)
case string:
return json.Unmarshal([]byte(v), &r)
default:
return fmt.Errorf("wrong type for repos: %T", v)
}
}

// Nullify ensures the valid flag for
// the sql.Null types are properly set.
//
// When a field within the Dashboard type is the zero
// value for the field, the valid flag is set to
// false causing it to be NULL in the database.
func (d *Dashboard) Nullify() *Dashboard {
if d == nil {
return nil
}

// check if the Name field should be false
if len(d.Name.String) == 0 {
d.Name.Valid = false
}

// check if the CreatedAt field should be false
if d.CreatedAt.Int64 == 0 {
d.CreatedAt.Valid = false
}

// check if the CreatedBy field should be false
if len(d.CreatedBy.String) == 0 {
d.CreatedBy.Valid = false
}

// check if the UpdatedAt field should be false
if d.UpdatedAt.Int64 == 0 {
d.UpdatedAt.Valid = false
}

// check if the UpdatedBy field should be false
if len(d.UpdatedBy.String) == 0 {
d.UpdatedBy.Valid = false
}

return d
}

// ToLibrary converts the Dashboard type
// to a library Dashboard type.
func (d *Dashboard) ToLibrary() *library.Dashboard {
dashboard := new(library.Dashboard)

dashboard.SetID(d.ID.String())
dashboard.SetName(d.Name.String)
dashboard.SetAdmins(d.Admins)
dashboard.SetCreatedAt(d.CreatedAt.Int64)
dashboard.SetCreatedBy(d.CreatedBy.String)
dashboard.SetUpdatedAt(d.UpdatedAt.Int64)
dashboard.SetUpdatedBy(d.UpdatedBy.String)
dashboard.SetRepos(d.Repos)

return dashboard
}

// Validate verifies the necessary fields for
// the Dashboard type are populated correctly.
func (d *Dashboard) Validate() error {
// verify the Name field is populated
if len(d.Name.String) == 0 {
return ErrEmptyDashName
}

// calculate total size of favorites
total := 0
for _, f := range d.Admins {
total += len(f)
}

// verify the Favorites field is within the database constraints
// len is to factor in number of comma separators included in the database field,
// removing 1 due to the last item not having an appended comma
if (total + len(d.Admins) - 1) > constants.DashboardAdminMaxSize {
return ErrExceededAdminLimit
}

// ensure that all Dashboard string fields
// that can be returned as JSON are sanitized
// to avoid unsafe HTML content
d.Name = sql.NullString{String: sanitize(d.Name.String), Valid: d.Name.Valid}

// ensure that all Favorites are sanitized
// to avoid unsafe HTML content
for i, v := range d.Admins {
d.Admins[i] = sanitize(v)
}

return nil
}

// DashboardFromLibrary converts the library Dashboard type
// to a database Dashboard type.
func DashboardFromLibrary(d *library.Dashboard) *Dashboard {
var (
id uuid.UUID
err error
)

if d.GetID() == "" {
id = uuid.New()
} else {
id, err = uuid.Parse(d.GetID())
if err != nil {
return nil
}
}

user := &Dashboard{
ID: id,
Name: sql.NullString{String: d.GetName(), Valid: true},
CreatedAt: sql.NullInt64{Int64: d.GetCreatedAt(), Valid: true},
CreatedBy: sql.NullString{String: d.GetCreatedBy(), Valid: true},
UpdatedAt: sql.NullInt64{Int64: d.GetUpdatedAt(), Valid: true},
UpdatedBy: sql.NullString{String: d.GetUpdatedBy(), Valid: true},
Admins: pq.StringArray(d.GetAdmins()),
Repos: d.GetRepos(),
}

return user.Nullify()
}
Loading
Loading