mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
#21955 <div> <a href="https://www.loom.com/share/ba40b440502845d2861fd3ec7611bade"> <p>[Demo] Deploy SCEP certificates from Network Device Enrollment Service (NDES) #21955 - Watch Video</p> </a> <a href="https://www.loom.com/share/ba40b440502845d2861fd3ec7611bade"> <img style="max-width:300px;" src="https://cdn.loom.com/sessions/thumbnails/ba40b440502845d2861fd3ec7611bade-84f2d88c9f5106c2-full-play.gif"> </a> </div> Note: A few remaining subtasks will be done in a follow-up PR. See #22123 for a detailed list. # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Added/updated tests - [x] Manual QA for all new/changed functionality
206 lines
3.9 KiB
Go
206 lines
3.9 KiB
Go
// Package optjson provides types that can be used to represent optional JSON
|
|
// values. The Set field indicates if the value was set (provided in the
|
|
// unmarshaled JSON payload) while the Valid field indicates if the value was
|
|
// not null.
|
|
//
|
|
// The types also support marshaling, respecting the Valid field (it will,
|
|
// however, be marshaled even if Set is false, although it will marshal to
|
|
// null).
|
|
//
|
|
// Inspired by https://www.calhoun.io/how-to-determine-if-a-json-key-has-been-set-to-null-or-not-provided/
|
|
package optjson
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
)
|
|
|
|
// String represents an optional string value.
|
|
type String struct {
|
|
Set bool
|
|
Valid bool
|
|
Value string
|
|
}
|
|
|
|
func SetString(s string) String {
|
|
return String{Set: true, Valid: true, Value: s}
|
|
}
|
|
|
|
func (s String) MarshalJSON() ([]byte, error) {
|
|
if !s.Valid {
|
|
return []byte("null"), nil
|
|
}
|
|
return json.Marshal(s.Value)
|
|
}
|
|
|
|
func (s *String) UnmarshalJSON(data []byte) error {
|
|
// If this method was called, the value was set.
|
|
s.Set = true
|
|
s.Valid = false
|
|
|
|
if bytes.Equal(data, []byte("null")) {
|
|
// The key was set to null, blank the value
|
|
s.Value = ""
|
|
return nil
|
|
}
|
|
|
|
// The key isn't set to null
|
|
var v string
|
|
if err := json.Unmarshal(data, &v); err != nil {
|
|
return err
|
|
}
|
|
s.Value = v
|
|
s.Valid = true
|
|
return nil
|
|
}
|
|
|
|
// Bool represents an optional boolean value.
|
|
type Bool struct {
|
|
Set bool
|
|
Valid bool
|
|
Value bool
|
|
}
|
|
|
|
func SetBool(b bool) Bool {
|
|
return Bool{Set: true, Valid: true, Value: b}
|
|
}
|
|
|
|
func (b Bool) MarshalJSON() ([]byte, error) {
|
|
if !b.Valid {
|
|
return []byte("null"), nil
|
|
}
|
|
return json.Marshal(b.Value)
|
|
}
|
|
|
|
func (b *Bool) UnmarshalJSON(data []byte) error {
|
|
// If this method was called, the value was set.
|
|
b.Set = true
|
|
b.Valid = false
|
|
|
|
if bytes.Equal(data, []byte("null")) {
|
|
// The key was set to null, blank the value
|
|
b.Value = false
|
|
return nil
|
|
}
|
|
|
|
// The key isn't set to null
|
|
var v bool
|
|
if err := json.Unmarshal(data, &v); err != nil {
|
|
return err
|
|
}
|
|
b.Value = v
|
|
b.Valid = true
|
|
return nil
|
|
}
|
|
|
|
// Int represents an optional integer value.
|
|
type Int struct {
|
|
Set bool
|
|
Valid bool
|
|
Value int
|
|
}
|
|
|
|
func SetInt(v int) Int {
|
|
return Int{Set: true, Valid: true, Value: v}
|
|
}
|
|
|
|
func (i Int) MarshalJSON() ([]byte, error) {
|
|
if !i.Valid {
|
|
return []byte("null"), nil
|
|
}
|
|
return json.Marshal(i.Value)
|
|
}
|
|
|
|
func (i *Int) UnmarshalJSON(data []byte) error {
|
|
// If this method was called, the value was set.
|
|
i.Set = true
|
|
i.Valid = false
|
|
|
|
if bytes.Equal(data, []byte("null")) {
|
|
// The key was set to null, blank the value
|
|
i.Value = 0
|
|
return nil
|
|
}
|
|
|
|
// The key isn't set to null
|
|
var v int
|
|
if err := json.Unmarshal(data, &v); err != nil {
|
|
return err
|
|
}
|
|
i.Value = v
|
|
i.Valid = true
|
|
return nil
|
|
}
|
|
|
|
type Slice[T any] struct {
|
|
Set bool
|
|
Valid bool
|
|
Value []T
|
|
}
|
|
|
|
func SetSlice[T any](s []T) Slice[T] {
|
|
return Slice[T]{Set: true, Valid: true, Value: s}
|
|
}
|
|
|
|
func (s Slice[T]) MarshalJSON() ([]byte, error) {
|
|
if !s.Valid {
|
|
return []byte("null"), nil
|
|
}
|
|
return json.Marshal(s.Value)
|
|
}
|
|
|
|
func (s *Slice[T]) UnmarshalJSON(data []byte) error {
|
|
// If this method was called, the value was set.
|
|
s.Set = true
|
|
s.Valid = false
|
|
|
|
if bytes.Equal(data, []byte("null")) {
|
|
// The key was set to null, blank the value
|
|
s.Value = []T{}
|
|
return nil
|
|
}
|
|
|
|
// The key isn't set to null
|
|
var v []T
|
|
if err := json.Unmarshal(data, &v); err != nil {
|
|
return err
|
|
}
|
|
s.Value = v
|
|
s.Valid = true
|
|
return nil
|
|
}
|
|
|
|
type Any[T any] struct {
|
|
Set bool
|
|
Valid bool
|
|
Value T
|
|
}
|
|
|
|
func (s Any[T]) MarshalJSON() ([]byte, error) {
|
|
if !s.Valid {
|
|
return []byte("null"), nil
|
|
}
|
|
return json.Marshal(s.Value)
|
|
}
|
|
|
|
func (s *Any[T]) UnmarshalJSON(data []byte) error {
|
|
// If this method was called, the value was set.
|
|
s.Set = true
|
|
s.Valid = false
|
|
|
|
if bytes.Equal(data, []byte("null")) {
|
|
// The key was set to null, set value to zero/default value
|
|
var zero T
|
|
s.Value = zero
|
|
return nil
|
|
}
|
|
|
|
// The key isn't set to null
|
|
var v T
|
|
if err := json.Unmarshal(data, &v); err != nil {
|
|
return err
|
|
}
|
|
s.Value = v
|
|
s.Valid = true
|
|
return nil
|
|
}
|