From ff1d95edab37c2c5a4606c821118e37be650d84b Mon Sep 17 00:00:00 2001 From: Sebastiaan de Schaetzen Date: Mon, 24 Mar 2025 16:15:52 +0100 Subject: [PATCH] Add ability to add hard drives --- .gitignore | 1 + data.go | 81 +++++++++--- main.go | 14 +- migrations/2_add_harddrives.sql | 8 ++ template_funcs.go | 24 ++++ templates/create_device_step1.gohtml | 6 +- templates/create_device_step2.gohtml | 111 +++++++++++----- templates/device.gohtml | 38 ++++-- views.go | 191 +++++++++++++++++++-------- 9 files changed, 354 insertions(+), 120 deletions(-) create mode 100644 migrations/2_add_harddrives.sql diff --git a/.gitignore b/.gitignore index fd2d067..a47f9f7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.db3 *.db3-* +*.db3.* *.iml .idea pcinv diff --git a/data.go b/data.go index ad08e7c..1ff9338 100644 --- a/data.go +++ b/data.go @@ -1,25 +1,14 @@ package main -import "gitea.seeseepuff.be/seeseemelk/mysqlite" +import ( + "fmt" + "gitea.seeseepuff.be/seeseemelk/mysqlite" +) -func (a *App) GetAllBrands() ([]string, error) { - var brands []string - var err error - for row := range a.db.Query("SELECT brand FROM assets GROUP BY brand ORDER BY brand ASC").Range(&err) { - var name string - err := row.Scan(&name) - if err != nil { - return nil, err - } - brands = append(brands, name) - } - return brands, err -} - -func (a *App) GetAllRAMTypes() ([]string, error) { +func (a *App) getAllTypes(column, table string) ([]string, error) { var types []string var err error - for row := range a.db.Query("SELECT type FROM info_ram GROUP BY type ORDER BY type ASC").Range(&err) { + for row := range a.db.Query(fmt.Sprintf("SELECT %s FROM %s GROUP BY %s ORDER BY %s ASC", column, table, column, column)).Range(&err) { var name string err := row.Scan(&name) if err != nil { @@ -30,6 +19,64 @@ func (a *App) GetAllRAMTypes() ([]string, error) { return types, err } +func (a *App) GetAllBrands() ([]string, error) { + return a.getAllTypes("brand", "assets") +} + +func (a *App) GetAllRamTypes() ([]string, error) { + return a.getAllTypes("type", "info_ram") +} + +func (a *App) GetAllHddTypes() ([]string, error) { + return a.getAllTypes("type", "info_hdd") +} + +func (a *App) GetAllHddFormFactors() ([]string, error) { + return a.getAllTypes("form_factor", "info_hdd") +} + +func (a *App) GetAllHddConnections() ([]string, error) { + return a.getAllTypes("connection", "info_hdd") +} + +func (a *App) GetAllHddSpeeds() ([]string, error) { + return a.getAllTypes("rpm", "info_hdd") +} + +func (a *App) GetAllGroups(vm *CreateDeviceVM) error { + var err error + vm.AssetBrands, err = a.GetAllBrands() + if err != nil { + return err + } + + vm.RamTypes, err = a.GetAllRamTypes() + if err != nil { + return err + } + + vm.HddTypes, err = a.GetAllHddTypes() + if err != nil { + return err + } + + vm.HddFormFactors, err = a.GetAllHddFormFactors() + if err != nil { + return err + } + + vm.HddFormFactors, err = a.GetAllHddConnections() + if err != nil { + return err + } + + vm.HddRpms, err = a.GetAllHddSpeeds() + if err != nil { + return err + } + return nil +} + func (a *App) GetAllTypes() ([]string, error) { var types []string var err error diff --git a/main.go b/main.go index 2567272..14526ea 100644 --- a/main.go +++ b/main.go @@ -43,12 +43,14 @@ func main() { templates, err := template.New("undefined.gohtml"). Funcs(template.FuncMap{ - "statusText": http.StatusText, - "createDeviceLink": createDeviceLink, - "formatMemorySize": formatMemorySize, - "formatMemoryPlainSize": formatMemoryPlainSize, - "formatType": formatType, - "isRamType": isRamType, + "statusText": http.StatusText, + "createDeviceLink": createDeviceLink, + "formatMemorySize": formatMemorySize, + "formatMemoryPlainSize": formatMemoryPlainSize, + "formatType": formatType, + "isRamType": isRamType, + "createSelectMenu": createSelectMenu, + "createSelectMenuDefault": createSelectMenuDefault, }). ParseFS(templateFS, "templates/*.gohtml") diff --git a/migrations/2_add_harddrives.sql b/migrations/2_add_harddrives.sql new file mode 100644 index 0000000..d2b0225 --- /dev/null +++ b/migrations/2_add_harddrives.sql @@ -0,0 +1,8 @@ +create table info_hdd ( + asset integer not null unique, + capacity integer, + type text, + form_factor text, + connection text, + rpm integer +); diff --git a/template_funcs.go b/template_funcs.go index c573463..c7d4481 100644 --- a/template_funcs.go +++ b/template_funcs.go @@ -91,7 +91,31 @@ func formatType(t string) string { switch t { case "ram": return "Random Access Memory" + case "hdd": + return "Hard Disk Drive" default: return t } } + +type SelectMenu struct { + Name string + Label string + Selected string + Options []string + DefaultValue string +} + +func createSelectMenu(name, label, selected string, options []string) SelectMenu { + return createSelectMenuDefault(name, label, selected, options, "Unknown") +} + +func createSelectMenuDefault(name, label, selected string, options []string, defaultValue string) SelectMenu { + return SelectMenu{ + Name: name, + Label: label, + Selected: selected, + Options: options, + DefaultValue: defaultValue, + } +} diff --git a/templates/create_device_step1.gohtml b/templates/create_device_step1.gohtml index c100beb..e4369e8 100644 --- a/templates/create_device_step1.gohtml +++ b/templates/create_device_step1.gohtml @@ -9,8 +9,10 @@ {{define "create_device_link"}} {{if .Qr}} -
  • Random Access Memory
  • +
  • {{"ram" | formatType}}
  • +
  • {{"hdd" | formatType}}
  • {{- else}} -
  • Random Access Memory
  • +
  • {{"ram" | formatType}}
  • +
  • {{"hdd" | formatType}}
  • {{- end}} {{end}} diff --git a/templates/create_device_step2.gohtml b/templates/create_device_step2.gohtml index d68927d..006210d 100644 --- a/templates/create_device_step2.gohtml +++ b/templates/create_device_step2.gohtml @@ -1,4 +1,4 @@ -{{- /*gotype: main.CreateDeviceVM */}} +{{- /*gotype: pcinv.CreateDeviceVM*/}} {{define "create_device_step2"}} {{template "header" "Create Device - Enter Device Data"}}
    @@ -21,7 +21,7 @@ - - {{range .RamTypes}} - {{if ne . "Unknown"}} - + {{if eq .Type "ram"}} +

    Memory Information

    + + + + - - - - - -
    + -
    - - -
    + + + + + + + + + + + + + {{end}} + + {{if eq .Type "hdd"}} +

    Hard Drive Information

    + + + + + + + + + + + + + + + + + + + + + +
    + + +
    {{template "create_device_select" createSelectMenu "hdd_type" "HDD Type" .HddType .HddTypes}}
    {{template "create_device_select" createSelectMenu "hdd_form_factor" "HDD Form Factor" .HddFormFactor .HddFormFactors}}
    {{template "create_device_select" createSelectMenu "hdd_connection" "HDD Connection" .HddConnection .HddConnections}}
    {{template "create_device_select" createSelectMenuDefault "hdd_rpm" "HDD RPM" .HddRpm .HddRpms "Not Applicable"}}
    + {{end}} {{if .IsEdit}} @@ -79,3 +116,15 @@
    {{template "footer"}} {{end}} + +{{define "create_device_select"}} + +{{end}} diff --git a/templates/device.gohtml b/templates/device.gohtml index 9bd9d9c..f47de45 100644 --- a/templates/device.gohtml +++ b/templates/device.gohtml @@ -19,14 +19,36 @@ {{.Description}} {{if eq .Type "ram"}} - - RAM Type: - {{.RamType}} - - - RAM Capacity: - {{.RamCapacity | formatMemorySize}} - + + RAM Type: + {{.RamType}} + + + RAM Capacity: + {{.RamCapacity | formatMemorySize}} + + {{end}} + {{if eq .Type "hdd"}} + + HDD Capacity: + {{.HddCapacity}} + + + HDD Type: + {{.HddType}} + + + Form Factor: + {{.HddFormFactor}} + + + Connection: + {{.HddConnection}} + + + RPM: + {{.HddRpm}} + {{end}} diff --git a/views.go b/views.go index 797200e..2f14ff3 100644 --- a/views.go +++ b/views.go @@ -59,13 +59,18 @@ func (a *App) getIndex(c *gin.Context) { } type DeviceVM struct { - Qr int - Name string - Brand string - Type string - Description string - RamType string - RamCapacity int + Qr int + Name string + Brand string + Type string + Description string + RamType string + RamCapacity int + HddCapacity int + HddType string + HddFormFactor string + HddConnection string + HddRpm int } func (a *App) getDevice(c *gin.Context) { @@ -106,26 +111,55 @@ func (a *App) getDevice(c *gin.Context) { c.AbortWithError(http.StatusInternalServerError, err) return } + } else if vm.Type == "hdd" { + err = a.db.Query("SELECT capacity, type, form_factor, connection, rpm FROM info_hdd WHERE asset = ?"). + Bind(qr). + ScanSingle(&vm.HddCapacity, &vm.HddType, &vm.HddFormFactor, &vm.HddConnection, &vm.HddRpm) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } } c.HTML(http.StatusOK, "device", vm) } type CreateDeviceVM struct { - Qr *int - Type string - Brands []string - RamTypes []string + IsEdit bool + + // Assets + Qr *int + Type string + + AssetBrand string + AssetBrands []string + AssetName string - AssetBrand string AssetDescription string - RamType string - RamCapacity int - IsEdit bool + + // RAM + RamType string + RamTypes []string + + RamCapacity int + + // HDD + HddCapacity int + + HddType string + HddTypes []string + HddFormFactor string + HddFormFactors []string + HddConnection string + HddConnections []string + HddRpm string + HddRpms []string } func (a *App) getCreateDevice(c *gin.Context) { + var err error vm := &CreateDeviceVM{} + vm.Type = c.Query("type") qr := c.Query("id") if qr != "" { @@ -137,22 +171,12 @@ func (a *App) getCreateDevice(c *gin.Context) { vm.Qr = &qrInt } - brands, err := a.GetAllBrands() + err = a.GetAllGroups(vm) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } - types, err := a.GetAllRAMTypes() - if err != nil { - c.AbortWithError(http.StatusInternalServerError, err) - return - } - - vm.Type = c.Query("type") - vm.Brands = brands - vm.RamTypes = types - if c.Query("edit") != "" && vm.Qr != nil { vm.IsEdit = true err = a.db.Query("SELECT name, type, brand, description FROM assets WHERE qr = ?"). @@ -170,6 +194,14 @@ func (a *App) getCreateDevice(c *gin.Context) { c.AbortWithError(http.StatusInternalServerError, err) return } + } else if vm.Type == "hdd" { + err = a.db.Query("SELECT capacity, type, form_factor, connection, rpm FROM info_hdd WHERE asset = ?"). + Bind(*vm.Qr). + ScanSingle(&vm.HddCapacity, &vm.HddType, &vm.HddFormFactor, &vm.HddConnection, &vm.HddRpm) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } } } @@ -183,13 +215,41 @@ func (a *App) postCreateDevice(c *gin.Context) { } assetType := c.PostForm("asset_type") + tx, err := a.db.Begin() + defer tx.MustRollback() + if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("error beginning tx: %v", err)) + return + } + + err = a.DeleteAsset(tx, qr) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("error removing assets: %v", err)) + return + } + err = tx.Query("INSERT INTO assets (qr, type, brand, name, description) VALUES (?, ?, ?, ?, ?)"). + Bind(qr, c.PostForm("asset_type"), c.PostForm("asset_brand"), c.PostForm("asset_name"), c.PostForm("asset_description")). + Exec() + if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("error inserting assets: %v", err)) + return + } + if assetType == "ram" { - err = a.postCreateDeviceRam(c, qr) + err = a.postCreateDeviceRam(c, qr, tx) + } else if assetType == "hdd" { + err = a.postCreateDeviceHdd(c, qr, tx) } else { c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("invalid type: %s", assetType)) return } + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } + + err = tx.Commit() if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return @@ -197,7 +257,7 @@ func (a *App) postCreateDevice(c *gin.Context) { c.Redirect(http.StatusSeeOther, "/") } -func (a *App) postCreateDeviceRam(c *gin.Context, qr int) error { +func (a *App) postCreateDeviceRam(c *gin.Context, qr int, tx *mysqlite.Tx) error { var err error capacity := 0 capacityString := c.PostForm("ram_capacity") @@ -219,27 +279,37 @@ func (a *App) postCreateDeviceRam(c *gin.Context, qr int) error { return errors.New("invalid ram_capacity_unit") } - tx, err := a.db.Begin() - defer tx.MustRollback() - if err != nil { - return err - } - - err = a.DeleteAsset(tx, qr) - - err = tx.Query("INSERT INTO assets (qr, type, brand, name, description) VALUES (?, ?, ?, ?, ?)"). - Bind(qr, c.PostForm("asset_type"), c.PostForm("asset_brand"), c.PostForm("asset_name"), c.PostForm("asset_description")). - Exec() - if err != nil { - return err - } - err = tx.Query("INSERT INTO info_ram (asset, type, capacity) VALUES (?, ?, ?)"). Bind(qr, c.PostForm("ram_type"), capacity).Exec() - if err != nil { - return err + return err +} + +func (a *App) postCreateDeviceHdd(c *gin.Context, qr int, tx *mysqlite.Tx) error { + var err error + capacity := 0 + capacityString := c.PostForm("hdd_capacity") + if capacityString != "" { + capacity, err = strconv.Atoi(c.PostForm("hdd_capacity")) + if err != nil { + return err + } } - return tx.Commit() + switch c.PostForm("hdd_capacity_unit") { + case "B": + case "KB": + capacity *= 1024 + case "MB": + capacity *= 1024 * 1024 + case "GB": + capacity *= 1024 * 1024 * 1024 + default: + return errors.New("invalid hdd_capacity_unit") + } + + err = tx.Query("INSERT INTO info_hdd (asset, capacity, type, form_factor, connection, rpm) VALUES (?, ?, ?, ?, ?, ?)"). + Bind(qr, capacity, c.PostForm("hdd_type"), c.PostForm("hdd_form_factor"), c.PostForm("hdd_connection"), c.PostForm("hdd_rpm")). + Exec() + return err } type BrowseVM struct { @@ -248,13 +318,18 @@ type BrowseVM struct { } type Asset struct { - Qr int - Name string - Brand string - Type string - Description string - RamType string - RamCapacity int + Qr int + Name string + Brand string + Type string + Description string + RamType string + RamCapacity int + HddCapacity int + HddType string + HddFormFactor string + HddConnection string + HddRpm int } func (a *App) getBrowse(c *gin.Context) { @@ -262,9 +337,11 @@ func (a *App) getBrowse(c *gin.Context) { types := c.QueryArray("type") query := `SELECT assets.qr, assets.name, assets.brand, assets.type, assets.description, - info_ram.type, info_ram.capacity + info_ram.type, info_ram.capacity, + info_hdd.capacity, info_hdd.type, info_hdd.form_factor, info_hdd.connection, info_hdd.rpm FROM assets - JOIN info_ram ON info_ram.asset = assets.qr + LEFT JOIN info_ram ON info_ram.asset = assets.qr + LEFT JOIN info_hdd ON info_hdd.asset = assets.qr WHERE 1=1` if len(brands) > 0 { query += " AND assets.brand IN (" + placeholders(len(brands)) + ")" @@ -280,7 +357,9 @@ func (a *App) getBrowse(c *gin.Context) { q := a.db.Query(query).Bind(brands, types) for row := range q.Range(&err) { var asset Asset - err := row.Scan(&asset.Qr, &asset.Name, &asset.Brand, &asset.Type, &asset.Description, &asset.RamType, &asset.RamCapacity) + err := row.Scan(&asset.Qr, &asset.Name, &asset.Brand, &asset.Type, &asset.Description, + &asset.RamType, &asset.RamCapacity, + &asset.HddCapacity, &asset.HddType, &asset.HddFormFactor, &asset.HddConnection, &asset.HddRpm) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return