Skip to content

Commit

Permalink
Added SliceToDb and SliceToWeb, Tests and updated README.md #3
Browse files Browse the repository at this point in the history
  • Loading branch information
ddibiasi committed Jul 15, 2024
1 parent d2fad80 commit 0d54ce5
Show file tree
Hide file tree
Showing 8 changed files with 564 additions and 235 deletions.
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,39 @@ updatedModel, err := wm.ApplyUpdate(old, new, role)
// }
```

`SliceToDb` and `SliceToWeb` work the same as `ToDb` and `ToWeb`, but take slices
instead of single structs.
```go
cat1 := SmallExample{Name: "Linus the cat", Comment: "A heckin' chonker"}
cat2 := SmallExample{Name: "Franz", Comment: "MEGACHONKER"}
cats := []SmallExample{cat1, cat2}

role := "staff"
dbCats, err := wm.SliceToDb(cats, role)
// [
// {
// "Name": "",
// "Comment": "A heckin' chonker"
// },
// {
// "Name": "",
// "Comment": "MEGACHONKER"
// },
// ]

webCats, err := wm.SliceWeb(cats, role)
// [
// {
// "Name": "Linus the cat",
// "Comment": "A heckin' chonker"
// },
// {
// "Name": "Franz",
// "Comment": "MEGACHONKER"
// },
// ]
```

Please do not rely solely on `wm` to "sanitize" your models before storing it in the database.
Make sure to check for SQL injections and other malicious techniques.

Expand Down Expand Up @@ -225,3 +258,36 @@ unauthorized can set:
&internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"Do not forget the tomato", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}
```

Slice operations:
```go

SliceToWeb()
---------------
staff can set:
&[]internal.SecretItem{internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:""}, internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:""}, internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:""}}

developer can set:
&[]internal.SecretItem{internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"", CanOnlyBeWrittenTo:""}, internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"", CanOnlyBeWrittenTo:""}, internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"", CanOnlyBeWrittenTo:""}}

admin can set:
&[]internal.SecretItem{internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"Do not forget the tomato", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}, internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"Do not forget the tomato", CanOnlyBeWrittenTnfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"Do not forget the tomato", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}}

unauthorized can set:
&[]internal.SecretItem{internal.SecretItem{Name:"", Comment:"", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:""}, internal.SecretItem{Name:"", Comment:"", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:""}, internal.SecretItem{Name:"", Comment:"", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:""}}


SliceToDb()
---------------
staff can set:
&[]internal.SecretItem{internal.SecretItem{Name:"", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}, internal.SecretItem{Name:"", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}, internal.SecretItem{Name:"", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}}

developer can set:
&[]internal.SecretItem{internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}, internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}, internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}}

admin can set:
&[]internal.SecretItem{internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"Do not forget the tomato", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}, internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"Do not forget the tomato", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}, internal.SecretItem{Name:"Crab Burger Recipe", Comment:"The recipe of the famous crusty crab burger", SecretInfo:"Bun, Pickle, Patty, Lettuce", TopSecret:"Do not forget the tomato", CanOnlyBeWrittenTo:"Hecho en Crustáceo Cascarudo"}}

unauthorized can set:
&[]internal.SecretItem{internal.SecretItem{Name:"", Comment:"", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:""}, internal.SecretItem{Name:"", Comment:"", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:""}, internal.SecretItem{Name:"", Comment:"", SecretInfo:"", TopSecret:"", CanOnlyBeWrittenTo:""}}
```

20 changes: 20 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ func main() {
CanOnlyBeWrittenTo: "Hecho en Crustáceo Cascarudo",
}

secretsSlice := []internal.SecretItem{secretItem, secretItem, secretItem}

roles := []string{"staff", "developer", "admin", "unauthorized"}

fmt.Printf("ToWeb()\n---------------\n")
Expand Down Expand Up @@ -51,4 +53,22 @@ func main() {
}
fmt.Printf("%s can set: \n%#v\n\n", role, updatedModel)
}

fmt.Printf("\nSliceToWeb()\n---------------\n")
for _, role := range roles {
webSlice, err := wm.SliceToWeb(secretsSlice, role)
if err != nil {
panic(err)
}
fmt.Printf("%s can set: \n%#v\n\n", role, webSlice)
}

fmt.Printf("\nSliceToDb()\n---------------\n")
for _, role := range roles {
webSlice, err := wm.SliceToDb(secretsSlice, role)
if err != nil {
panic(err)
}
fmt.Printf("%s can set: \n%#v\n\n", role, webSlice)
}
}
28 changes: 28 additions & 0 deletions mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,40 @@ func ToWeb[T any](dbModel T, role string) (webModel *T, err error) {
return doMapping(dbModel, nil, role, toWebActions)
}

// SliceToWeb converts a slice of dbModels to a slice of webModels.
// Only sets fields on webModels the supplied role is allowed to read from (R or RW).
func SliceToWeb[T any](dbSlice []T, role string) (*[]T, error) {
webSlice := make([]T, len(dbSlice))
for i, item := range dbSlice {
m, err := doMapping(item, nil, role, toWebActions)
if err != nil {
return nil, err
}
webSlice[i] = *m
}
return &webSlice, nil
}

// ToDb converts webModel to a dbModel.
// Only sets fields on dbModel the supplied role is allowed to write to (W or RW).
func ToDb[T any](webModel T, role string) (dbModel *T, err error) {
return doMapping(webModel, nil, role, toDBActions)
}

// SliceToDb converts a slice of webModels to a slice of dbModels.
// Only sets fields on dbModels the supplied role is allowed to write to (W or RW).
func SliceToDb[T any](webSlice []T, role string) (*[]T, error) {
dbSlice := make([]T, len(webSlice))
for i, item := range webSlice {
m, err := doMapping(item, nil, role, toDBActions)
if err != nil {
return nil, err
}
dbSlice[i] = *m
}
return &dbSlice, nil
}

// ApplyUpdate applies changes from newModel to oldModel.
// Only sets fields from newModel on oldModel,
// if the supplied role is allowed to write to (W or RW).
Expand Down
70 changes: 70 additions & 0 deletions mapper_db_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package wm

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestToDbAdmin(t *testing.T) {
role := "admin"

webModel, err := ToDb(secretItem, role)
if err != nil {
t.Fatalf("Error creating dbModel: %v", err)
}

// admin is allowed to write to all fields
assert.Equal(t, secretItem.Name, webModel.Name)
assert.Equal(t, secretItem.Comment, webModel.Comment)
assert.Equal(t, secretItem.SecretInfo, webModel.SecretInfo)
assert.Equal(t, secretItem.TopSecret, webModel.TopSecret)
assert.Equal(t, secretItem.CanOnlyBeWrittenTo, webModel.CanOnlyBeWrittenTo)
}

func TestToDbDeveloper(t *testing.T) {
role := "developer"

webModel, err := ToDb(secretItem, role)
if err != nil {
t.Fatalf("Error creating dbModel: %v", err)
}

// developer is not allowed to write to all fields
assert.Equal(t, secretItem.Name, webModel.Name)
assert.Equal(t, secretItem.Comment, webModel.Comment)
assert.Empty(t, webModel.SecretInfo)
assert.Empty(t, webModel.TopSecret)
assert.Equal(t, secretItem.CanOnlyBeWrittenTo, webModel.CanOnlyBeWrittenTo)
}

func TestToDbStaff(t *testing.T) {
role := "staff"

webModel, err := ToDb(secretItem, role)
if err != nil {
t.Fatalf("Error creating dbModel: %v", err)
}

// staff is not allowed to write to all fields
assert.Empty(t, webModel.Name)
assert.Equal(t, secretItem.Comment, webModel.Comment)
assert.Empty(t, webModel.SecretInfo)
assert.Empty(t, webModel.TopSecret)
assert.Equal(t, secretItem.CanOnlyBeWrittenTo, webModel.CanOnlyBeWrittenTo)
}

func TestToDbUnauthorized(t *testing.T) {
role := "unauthorized"

webModel, err := ToDb(secretItem, role)
if err != nil {
t.Fatalf("Error creating dbModel: %v", err)
}

// unauthorized is not allowed to write to any fields
assert.Empty(t, webModel.Name)
assert.Empty(t, webModel.Comment)
assert.Empty(t, webModel.SecretInfo)
assert.Empty(t, webModel.TopSecret)
assert.Empty(t, webModel.CanOnlyBeWrittenTo)
}
Loading

0 comments on commit 0d54ce5

Please sign in to comment.