mirror of
https://github.com/hay-kot/homebox.git
synced 2025-08-05 09:10:26 +00:00
ensure export contains locations path
This commit is contained in:
parent
30fb679b95
commit
e4562cd770
8 changed files with 108 additions and 25 deletions
|
@ -1,7 +0,0 @@
|
|||
Import Ref,Location,Labels,Quantity,Name,Description,Insured,Serial Number,Mode Number,Manufacturer,Notes,Purchase From,Purchased Price,Purchased Time,Lifetime Warranty,Warranty Expires,Warranty Details,Sold To,Sold Price,Sold Time,Sold Notes
|
||||
A,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,Description 1,TRUE,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021,
|
||||
B,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,Description 2,FALSE,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,10/15/2021,,,,10/15/2021,
|
||||
C,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,Description 3,TRUE,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021,
|
||||
D,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,Description 4,FALSE,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,10/21/2020,,,,10/21/2020,
|
||||
E,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,Description 5,TRUE,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,10/14/2020,,,,10/14/2020,
|
||||
F,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,Description 6,FALSE,,39351,Honeywell,,Amazon,65.98,09/30/2020,,09/30/2020,,,,09/30/2020,
|
|
|
@ -1,7 +0,0 @@
|
|||
Import Ref Location Labels Quantity Name Description Insured Serial Number Mode Number Manufacturer Notes Purchase From Purchased Price Purchased Time Lifetime Warranty Warranty Expires Warranty Details Sold To Sold Price Sold Time Sold Notes
|
||||
A Garage IOT;Home Assistant; Z-Wave 1 Zooz Universal Relay ZEN17 Description 1 TRUE ZEN17 Zooz Amazon 39.95 10/13/2021 10/13/2021 10/13/2021
|
||||
B Living Room IOT;Home Assistant; Z-Wave 1 Zooz Motion Sensor Description 2 FALSE ZSE18 Zooz Amazon 29.95 10/15/2021 10/15/2021 10/15/2021
|
||||
C Office IOT;Home Assistant; Z-Wave 1 Zooz 110v Power Switch Description 3 TRUE ZEN15 Zooz Amazon 39.95 10/13/2021 10/13/2021 10/13/2021
|
||||
D Downstairs IOT;Home Assistant; Z-Wave 1 Ecolink Z-Wave PIR Motion Sensor Description 4 FALSE PIRZWAVE2.5-ECO Ecolink Amazon 35.58 10/21/2020 10/21/2020 10/21/2020
|
||||
E Entry IOT;Home Assistant; Z-Wave 1 Yale Security Touchscreen Deadbolt Description 5 TRUE YRD226ZW2619 Yale Amazon 120.39 10/14/2020 10/14/2020 10/14/2020
|
||||
F Kitchen IOT;Home Assistant; Z-Wave 1 Smart Rocker Light Dimmer Description 6 FALSE 39351 Honeywell Amazon 65.98 09/30/2020 09/30/2020 09/30/2020
|
|
|
@ -83,3 +83,13 @@ func parseLocationString(s string) LocationString {
|
|||
func (csf LocationString) String() string {
|
||||
return strings.Join(csf, " / ")
|
||||
}
|
||||
|
||||
func fromPathSlice(s []repo.LocationPath) LocationString {
|
||||
v := make(LocationString, len(s))
|
||||
|
||||
for i := range s {
|
||||
v[i] = s[i].Name
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package reporting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
@ -8,6 +9,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
@ -151,7 +153,7 @@ func (s *IOSheet) Read(data io.Reader) error {
|
|||
}
|
||||
|
||||
// Write writes the sheet to a writer.
|
||||
func (s *IOSheet) ReadItems(items []repo.ItemOut) {
|
||||
func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid.UUID, repos *repo.AllRepos) error {
|
||||
s.Rows = make([]ExportTSVRow, len(items))
|
||||
|
||||
extraHeaders := map[string]struct{}{}
|
||||
|
@ -160,7 +162,15 @@ func (s *IOSheet) ReadItems(items []repo.ItemOut) {
|
|||
item := items[i]
|
||||
|
||||
// TODO: Support fetching nested locations
|
||||
locString := LocationString{item.Location.Name}
|
||||
locId := item.Location.ID
|
||||
|
||||
locPaths, err := repos.Locations.PathForLoc(context.Background(), GID, locId)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not get location path")
|
||||
return err
|
||||
}
|
||||
|
||||
locString := fromPathSlice(locPaths)
|
||||
|
||||
labelString := make([]string, len(item.Labels))
|
||||
|
||||
|
@ -238,6 +248,8 @@ func (s *IOSheet) ReadItems(items []repo.ItemOut) {
|
|||
for _, h := range customHeaders {
|
||||
s.headers = append(s.headers, "HB.field."+h)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Writes the current sheet to a writer in TSV format.
|
||||
|
|
|
@ -20,12 +20,6 @@ var (
|
|||
|
||||
//go:embed .testdata/import/types.csv
|
||||
customTypesImportCSV []byte
|
||||
|
||||
//go:embed .testdata/import.csv
|
||||
CSVData_Comma []byte
|
||||
|
||||
//go:embed .testdata/import.tsv
|
||||
CSVData_Tab []byte
|
||||
)
|
||||
|
||||
func TestSheet_Read(t *testing.T) {
|
||||
|
@ -189,7 +183,7 @@ func Test_determineSeparator(t *testing.T) {
|
|||
{
|
||||
name: "comma",
|
||||
args: args{
|
||||
data: CSVData_Comma,
|
||||
data: []byte("a,b,c"),
|
||||
},
|
||||
want: ',',
|
||||
wantErr: false,
|
||||
|
@ -197,7 +191,7 @@ func Test_determineSeparator(t *testing.T) {
|
|||
{
|
||||
name: "tab",
|
||||
args: args{
|
||||
data: CSVData_Tab,
|
||||
data: []byte("a\tb\tc"),
|
||||
},
|
||||
want: '\t',
|
||||
wantErr: false,
|
||||
|
|
|
@ -337,7 +337,10 @@ func (svc *ItemService) ExportTSV(ctx context.Context, GID uuid.UUID) ([][]strin
|
|||
|
||||
sheet := reporting.IOSheet{}
|
||||
|
||||
sheet.ReadItems(items)
|
||||
err = sheet.ReadItems(ctx, items, GID, svc.repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sheet.TSV()
|
||||
}
|
||||
|
|
|
@ -249,6 +249,56 @@ type TreeQuery struct {
|
|||
WithItems bool `json:"withItems" schema:"withItems"`
|
||||
}
|
||||
|
||||
type LocationPath struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (lr *LocationRepository) PathForLoc(ctx context.Context, GID, locID uuid.UUID) ([]LocationPath, error) {
|
||||
query := `WITH RECURSIVE location_path AS (
|
||||
SELECT id, name, location_children
|
||||
FROM locations
|
||||
WHERE id = ? -- Replace ? with the ID of the item's location
|
||||
AND group_locations = ? -- Replace ? with the ID of the group
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT loc.id, loc.name, loc.location_children
|
||||
FROM locations loc
|
||||
JOIN location_path lp ON loc.id = lp.location_children
|
||||
)
|
||||
|
||||
SELECT id, name
|
||||
FROM location_path`
|
||||
|
||||
rows, err := lr.db.Sql().QueryContext(ctx, query, locID, GID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var locations []LocationPath
|
||||
|
||||
for rows.Next() {
|
||||
var location LocationPath
|
||||
if err := rows.Scan(&location.ID, &location.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
locations = append(locations, location)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Reverse the order of the locations so that the root is last
|
||||
for i := len(locations)/2 - 1; i >= 0; i-- {
|
||||
opp := len(locations) - 1 - i
|
||||
locations[i], locations[opp] = locations[opp], locations[i]
|
||||
}
|
||||
|
||||
return locations, nil
|
||||
}
|
||||
|
||||
func (lr *LocationRepository) Tree(ctx context.Context, GID uuid.UUID, tq TreeQuery) ([]TreeItem, error) {
|
||||
query := `
|
||||
WITH recursive location_tree(id, NAME, parent_id, level, node_type) AS
|
||||
|
|
|
@ -146,6 +146,34 @@ func TestItemRepository_TreeQuery(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLocationRepository_PathForLoc(t *testing.T) {
|
||||
locs := useLocations(t, 3)
|
||||
|
||||
// Set relations 3 -> 2 -> 1
|
||||
for i := 0; i < 2; i++ {
|
||||
_, err := tRepos.Locations.UpdateByGroup(context.Background(), tGroup.ID, locs[i].ID, LocationUpdate{
|
||||
ID: locs[i].ID,
|
||||
ParentID: locs[i+1].ID,
|
||||
Name: locs[i].Name,
|
||||
Description: locs[i].Description,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
last := locs[0]
|
||||
|
||||
path, err := tRepos.Locations.PathForLoc(context.Background(), tGroup.ID, last.ID)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, len(path))
|
||||
|
||||
// Check path and order
|
||||
for i, loc := range path {
|
||||
assert.Equal(t, locs[i].ID, loc.ID)
|
||||
assert.Equal(t, locs[i].Name, loc.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertLocationsToTree(t *testing.T) {
|
||||
uuid1, uuid2, uuid3, uuid4 := uuid.New(), uuid.New(), uuid.New(), uuid.New()
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue