mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-02 20:02:25 -06:00 
			
		
		
		
	* Add Swagger spec test script * Fix Swagger spec errors not related to statuses with polls * Add API tests that post a status with a poll * Fix creating a status with a poll from form params * Fix Swagger spec errors related to statuses with polls (this is the last error) * Fix Swagger spec warnings not related to unused definitions * Suppress a duplicate list update params definition that was somehow causing wrong param names * Add Swagger test to CI - updates Drone config - vendorizes go-swagger - fixes a file extension issue that caused the test script to generate JSON instead of YAML with the vendorized version * Put `Sample: ` on its own line everywhere * Remove unused id param from emojiCategoriesGet * Add 5 more pairs of profile fields to account update API Swagger * Remove Swagger prefix from dummy fields It makes the generated code look weird * Manually annotate params for statusCreate operation * Fix all remaining Swagger spec warnings - Change some models into operation parameters - Ignore models that already correspond to manually documented operation parameters but can't be trivially changed (those with file fields) * Documented that creating a status with scheduled_at isn't implemented yet * sign drone.yml * Fix filter API Swagger errors * fixup! Fix filter API Swagger errors --------- Co-authored-by: tobi <tobi.smethurst@protonmail.com>
		
			
				
	
	
		
			420 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			420 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// reflectwalk is a package that allows you to "walk" complex structures
 | 
						|
// similar to how you may "walk" a filesystem: visiting every element one
 | 
						|
// by one and calling callback functions allowing you to handle and manipulate
 | 
						|
// those elements.
 | 
						|
package reflectwalk
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"reflect"
 | 
						|
)
 | 
						|
 | 
						|
// PrimitiveWalker implementations are able to handle primitive values
 | 
						|
// within complex structures. Primitive values are numbers, strings,
 | 
						|
// booleans, funcs, chans.
 | 
						|
//
 | 
						|
// These primitive values are often members of more complex
 | 
						|
// structures (slices, maps, etc.) that are walkable by other interfaces.
 | 
						|
type PrimitiveWalker interface {
 | 
						|
	Primitive(reflect.Value) error
 | 
						|
}
 | 
						|
 | 
						|
// InterfaceWalker implementations are able to handle interface values as they
 | 
						|
// are encountered during the walk.
 | 
						|
type InterfaceWalker interface {
 | 
						|
	Interface(reflect.Value) error
 | 
						|
}
 | 
						|
 | 
						|
// MapWalker implementations are able to handle individual elements
 | 
						|
// found within a map structure.
 | 
						|
type MapWalker interface {
 | 
						|
	Map(m reflect.Value) error
 | 
						|
	MapElem(m, k, v reflect.Value) error
 | 
						|
}
 | 
						|
 | 
						|
// SliceWalker implementations are able to handle slice elements found
 | 
						|
// within complex structures.
 | 
						|
type SliceWalker interface {
 | 
						|
	Slice(reflect.Value) error
 | 
						|
	SliceElem(int, reflect.Value) error
 | 
						|
}
 | 
						|
 | 
						|
// ArrayWalker implementations are able to handle array elements found
 | 
						|
// within complex structures.
 | 
						|
type ArrayWalker interface {
 | 
						|
	Array(reflect.Value) error
 | 
						|
	ArrayElem(int, reflect.Value) error
 | 
						|
}
 | 
						|
 | 
						|
// StructWalker is an interface that has methods that are called for
 | 
						|
// structs when a Walk is done.
 | 
						|
type StructWalker interface {
 | 
						|
	Struct(reflect.Value) error
 | 
						|
	StructField(reflect.StructField, reflect.Value) error
 | 
						|
}
 | 
						|
 | 
						|
// EnterExitWalker implementations are notified before and after
 | 
						|
// they walk deeper into complex structures (into struct fields,
 | 
						|
// into slice elements, etc.)
 | 
						|
type EnterExitWalker interface {
 | 
						|
	Enter(Location) error
 | 
						|
	Exit(Location) error
 | 
						|
}
 | 
						|
 | 
						|
// PointerWalker implementations are notified when the value they're
 | 
						|
// walking is a pointer or not. Pointer is called for _every_ value whether
 | 
						|
// it is a pointer or not.
 | 
						|
type PointerWalker interface {
 | 
						|
	PointerEnter(bool) error
 | 
						|
	PointerExit(bool) error
 | 
						|
}
 | 
						|
 | 
						|
// PointerValueWalker implementations are notified with the value of
 | 
						|
// a particular pointer when a pointer is walked. Pointer is called
 | 
						|
// right before PointerEnter.
 | 
						|
type PointerValueWalker interface {
 | 
						|
	Pointer(reflect.Value) error
 | 
						|
}
 | 
						|
 | 
						|
// SkipEntry can be returned from walk functions to skip walking
 | 
						|
// the value of this field. This is only valid in the following functions:
 | 
						|
//
 | 
						|
//   - Struct: skips all fields from being walked
 | 
						|
//   - StructField: skips walking the struct value
 | 
						|
//
 | 
						|
var SkipEntry = errors.New("skip this entry")
 | 
						|
 | 
						|
// Walk takes an arbitrary value and an interface and traverses the
 | 
						|
// value, calling callbacks on the interface if they are supported.
 | 
						|
// The interface should implement one or more of the walker interfaces
 | 
						|
// in this package, such as PrimitiveWalker, StructWalker, etc.
 | 
						|
func Walk(data, walker interface{}) (err error) {
 | 
						|
	v := reflect.ValueOf(data)
 | 
						|
	ew, ok := walker.(EnterExitWalker)
 | 
						|
	if ok {
 | 
						|
		err = ew.Enter(WalkLoc)
 | 
						|
	}
 | 
						|
 | 
						|
	if err == nil {
 | 
						|
		err = walk(v, walker)
 | 
						|
	}
 | 
						|
 | 
						|
	if ok && err == nil {
 | 
						|
		err = ew.Exit(WalkLoc)
 | 
						|
	}
 | 
						|
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func walk(v reflect.Value, w interface{}) (err error) {
 | 
						|
	// Determine if we're receiving a pointer and if so notify the walker.
 | 
						|
	// The logic here is convoluted but very important (tests will fail if
 | 
						|
	// almost any part is changed). I will try to explain here.
 | 
						|
	//
 | 
						|
	// First, we check if the value is an interface, if so, we really need
 | 
						|
	// to check the interface's VALUE to see whether it is a pointer.
 | 
						|
	//
 | 
						|
	// Check whether the value is then a pointer. If so, then set pointer
 | 
						|
	// to true to notify the user.
 | 
						|
	//
 | 
						|
	// If we still have a pointer or an interface after the indirections, then
 | 
						|
	// we unwrap another level
 | 
						|
	//
 | 
						|
	// At this time, we also set "v" to be the dereferenced value. This is
 | 
						|
	// because once we've unwrapped the pointer we want to use that value.
 | 
						|
	pointer := false
 | 
						|
	pointerV := v
 | 
						|
 | 
						|
	for {
 | 
						|
		if pointerV.Kind() == reflect.Interface {
 | 
						|
			if iw, ok := w.(InterfaceWalker); ok {
 | 
						|
				if err = iw.Interface(pointerV); err != nil {
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			pointerV = pointerV.Elem()
 | 
						|
		}
 | 
						|
 | 
						|
		if pointerV.Kind() == reflect.Ptr {
 | 
						|
			if pw, ok := w.(PointerValueWalker); ok {
 | 
						|
				if err = pw.Pointer(pointerV); err != nil {
 | 
						|
					if err == SkipEntry {
 | 
						|
						// Skip the rest of this entry but clear the error
 | 
						|
						return nil
 | 
						|
					}
 | 
						|
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			pointer = true
 | 
						|
			v = reflect.Indirect(pointerV)
 | 
						|
		}
 | 
						|
		if pw, ok := w.(PointerWalker); ok {
 | 
						|
			if err = pw.PointerEnter(pointer); err != nil {
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			defer func(pointer bool) {
 | 
						|
				if err != nil {
 | 
						|
					return
 | 
						|
				}
 | 
						|
 | 
						|
				err = pw.PointerExit(pointer)
 | 
						|
			}(pointer)
 | 
						|
		}
 | 
						|
 | 
						|
		if pointer {
 | 
						|
			pointerV = v
 | 
						|
		}
 | 
						|
		pointer = false
 | 
						|
 | 
						|
		// If we still have a pointer or interface we have to indirect another level.
 | 
						|
		switch pointerV.Kind() {
 | 
						|
		case reflect.Ptr, reflect.Interface:
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		break
 | 
						|
	}
 | 
						|
 | 
						|
	// We preserve the original value here because if it is an interface
 | 
						|
	// type, we want to pass that directly into the walkPrimitive, so that
 | 
						|
	// we can set it.
 | 
						|
	originalV := v
 | 
						|
	if v.Kind() == reflect.Interface {
 | 
						|
		v = v.Elem()
 | 
						|
	}
 | 
						|
 | 
						|
	k := v.Kind()
 | 
						|
	if k >= reflect.Int && k <= reflect.Complex128 {
 | 
						|
		k = reflect.Int
 | 
						|
	}
 | 
						|
 | 
						|
	switch k {
 | 
						|
	// Primitives
 | 
						|
	case reflect.Bool, reflect.Chan, reflect.Func, reflect.Int, reflect.String, reflect.Invalid:
 | 
						|
		err = walkPrimitive(originalV, w)
 | 
						|
		return
 | 
						|
	case reflect.Map:
 | 
						|
		err = walkMap(v, w)
 | 
						|
		return
 | 
						|
	case reflect.Slice:
 | 
						|
		err = walkSlice(v, w)
 | 
						|
		return
 | 
						|
	case reflect.Struct:
 | 
						|
		err = walkStruct(v, w)
 | 
						|
		return
 | 
						|
	case reflect.Array:
 | 
						|
		err = walkArray(v, w)
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		panic("unsupported type: " + k.String())
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func walkMap(v reflect.Value, w interface{}) error {
 | 
						|
	ew, ewok := w.(EnterExitWalker)
 | 
						|
	if ewok {
 | 
						|
		ew.Enter(Map)
 | 
						|
	}
 | 
						|
 | 
						|
	if mw, ok := w.(MapWalker); ok {
 | 
						|
		if err := mw.Map(v); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for _, k := range v.MapKeys() {
 | 
						|
		kv := v.MapIndex(k)
 | 
						|
 | 
						|
		if mw, ok := w.(MapWalker); ok {
 | 
						|
			if err := mw.MapElem(v, k, kv); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		ew, ok := w.(EnterExitWalker)
 | 
						|
		if ok {
 | 
						|
			ew.Enter(MapKey)
 | 
						|
		}
 | 
						|
 | 
						|
		if err := walk(k, w); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if ok {
 | 
						|
			ew.Exit(MapKey)
 | 
						|
			ew.Enter(MapValue)
 | 
						|
		}
 | 
						|
 | 
						|
		// get the map value again as it may have changed in the MapElem call
 | 
						|
		if err := walk(v.MapIndex(k), w); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if ok {
 | 
						|
			ew.Exit(MapValue)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if ewok {
 | 
						|
		ew.Exit(Map)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func walkPrimitive(v reflect.Value, w interface{}) error {
 | 
						|
	if pw, ok := w.(PrimitiveWalker); ok {
 | 
						|
		return pw.Primitive(v)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func walkSlice(v reflect.Value, w interface{}) (err error) {
 | 
						|
	ew, ok := w.(EnterExitWalker)
 | 
						|
	if ok {
 | 
						|
		ew.Enter(Slice)
 | 
						|
	}
 | 
						|
 | 
						|
	if sw, ok := w.(SliceWalker); ok {
 | 
						|
		if err := sw.Slice(v); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for i := 0; i < v.Len(); i++ {
 | 
						|
		elem := v.Index(i)
 | 
						|
 | 
						|
		if sw, ok := w.(SliceWalker); ok {
 | 
						|
			if err := sw.SliceElem(i, elem); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		ew, ok := w.(EnterExitWalker)
 | 
						|
		if ok {
 | 
						|
			ew.Enter(SliceElem)
 | 
						|
		}
 | 
						|
 | 
						|
		if err := walk(elem, w); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if ok {
 | 
						|
			ew.Exit(SliceElem)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	ew, ok = w.(EnterExitWalker)
 | 
						|
	if ok {
 | 
						|
		ew.Exit(Slice)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func walkArray(v reflect.Value, w interface{}) (err error) {
 | 
						|
	ew, ok := w.(EnterExitWalker)
 | 
						|
	if ok {
 | 
						|
		ew.Enter(Array)
 | 
						|
	}
 | 
						|
 | 
						|
	if aw, ok := w.(ArrayWalker); ok {
 | 
						|
		if err := aw.Array(v); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for i := 0; i < v.Len(); i++ {
 | 
						|
		elem := v.Index(i)
 | 
						|
 | 
						|
		if aw, ok := w.(ArrayWalker); ok {
 | 
						|
			if err := aw.ArrayElem(i, elem); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		ew, ok := w.(EnterExitWalker)
 | 
						|
		if ok {
 | 
						|
			ew.Enter(ArrayElem)
 | 
						|
		}
 | 
						|
 | 
						|
		if err := walk(elem, w); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if ok {
 | 
						|
			ew.Exit(ArrayElem)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	ew, ok = w.(EnterExitWalker)
 | 
						|
	if ok {
 | 
						|
		ew.Exit(Array)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func walkStruct(v reflect.Value, w interface{}) (err error) {
 | 
						|
	ew, ewok := w.(EnterExitWalker)
 | 
						|
	if ewok {
 | 
						|
		ew.Enter(Struct)
 | 
						|
	}
 | 
						|
 | 
						|
	skip := false
 | 
						|
	if sw, ok := w.(StructWalker); ok {
 | 
						|
		err = sw.Struct(v)
 | 
						|
		if err == SkipEntry {
 | 
						|
			skip = true
 | 
						|
			err = nil
 | 
						|
		}
 | 
						|
		if err != nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if !skip {
 | 
						|
		vt := v.Type()
 | 
						|
		for i := 0; i < vt.NumField(); i++ {
 | 
						|
			sf := vt.Field(i)
 | 
						|
			f := v.FieldByIndex([]int{i})
 | 
						|
 | 
						|
			if sw, ok := w.(StructWalker); ok {
 | 
						|
				err = sw.StructField(sf, f)
 | 
						|
 | 
						|
				// SkipEntry just pretends this field doesn't even exist
 | 
						|
				if err == SkipEntry {
 | 
						|
					continue
 | 
						|
				}
 | 
						|
 | 
						|
				if err != nil {
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			ew, ok := w.(EnterExitWalker)
 | 
						|
			if ok {
 | 
						|
				ew.Enter(StructField)
 | 
						|
			}
 | 
						|
 | 
						|
			err = walk(f, w)
 | 
						|
			if err != nil {
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			if ok {
 | 
						|
				ew.Exit(StructField)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if ewok {
 | 
						|
		ew.Exit(Struct)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 |