mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-02 16:52: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>
		
			
				
	
	
		
			312 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2015 go-swagger maintainers
 | 
						|
//
 | 
						|
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
// you may not use this file except in compliance with the License.
 | 
						|
// You may obtain a copy of the License at
 | 
						|
//
 | 
						|
//    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, software
 | 
						|
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
// See the License for the specific language governing permissions and
 | 
						|
// limitations under the License.
 | 
						|
 | 
						|
package swag
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"encoding/json"
 | 
						|
	"log"
 | 
						|
	"reflect"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
 | 
						|
	"github.com/mailru/easyjson/jlexer"
 | 
						|
	"github.com/mailru/easyjson/jwriter"
 | 
						|
)
 | 
						|
 | 
						|
// nullJSON represents a JSON object with null type
 | 
						|
var nullJSON = []byte("null")
 | 
						|
 | 
						|
// DefaultJSONNameProvider the default cache for types
 | 
						|
var DefaultJSONNameProvider = NewNameProvider()
 | 
						|
 | 
						|
const comma = byte(',')
 | 
						|
 | 
						|
var closers map[byte]byte
 | 
						|
 | 
						|
func init() {
 | 
						|
	closers = map[byte]byte{
 | 
						|
		'{': '}',
 | 
						|
		'[': ']',
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type ejMarshaler interface {
 | 
						|
	MarshalEasyJSON(w *jwriter.Writer)
 | 
						|
}
 | 
						|
 | 
						|
type ejUnmarshaler interface {
 | 
						|
	UnmarshalEasyJSON(w *jlexer.Lexer)
 | 
						|
}
 | 
						|
 | 
						|
// WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaler
 | 
						|
// so it takes the fastest option available.
 | 
						|
func WriteJSON(data interface{}) ([]byte, error) {
 | 
						|
	if d, ok := data.(ejMarshaler); ok {
 | 
						|
		jw := new(jwriter.Writer)
 | 
						|
		d.MarshalEasyJSON(jw)
 | 
						|
		return jw.BuildBytes()
 | 
						|
	}
 | 
						|
	if d, ok := data.(json.Marshaler); ok {
 | 
						|
		return d.MarshalJSON()
 | 
						|
	}
 | 
						|
	return json.Marshal(data)
 | 
						|
}
 | 
						|
 | 
						|
// ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaler
 | 
						|
// so it takes the fastest option available
 | 
						|
func ReadJSON(data []byte, value interface{}) error {
 | 
						|
	trimmedData := bytes.Trim(data, "\x00")
 | 
						|
	if d, ok := value.(ejUnmarshaler); ok {
 | 
						|
		jl := &jlexer.Lexer{Data: trimmedData}
 | 
						|
		d.UnmarshalEasyJSON(jl)
 | 
						|
		return jl.Error()
 | 
						|
	}
 | 
						|
	if d, ok := value.(json.Unmarshaler); ok {
 | 
						|
		return d.UnmarshalJSON(trimmedData)
 | 
						|
	}
 | 
						|
	return json.Unmarshal(trimmedData, value)
 | 
						|
}
 | 
						|
 | 
						|
// DynamicJSONToStruct converts an untyped json structure into a struct
 | 
						|
func DynamicJSONToStruct(data interface{}, target interface{}) error {
 | 
						|
	// TODO: convert straight to a json typed map  (mergo + iterate?)
 | 
						|
	b, err := WriteJSON(data)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	return ReadJSON(b, target)
 | 
						|
}
 | 
						|
 | 
						|
// ConcatJSON concatenates multiple json objects efficiently
 | 
						|
func ConcatJSON(blobs ...[]byte) []byte {
 | 
						|
	if len(blobs) == 0 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	last := len(blobs) - 1
 | 
						|
	for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
 | 
						|
		// strips trailing null objects
 | 
						|
		last--
 | 
						|
		if last < 0 {
 | 
						|
			// there was nothing but "null"s or nil...
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if last == 0 {
 | 
						|
		return blobs[0]
 | 
						|
	}
 | 
						|
 | 
						|
	var opening, closing byte
 | 
						|
	var idx, a int
 | 
						|
	buf := bytes.NewBuffer(nil)
 | 
						|
 | 
						|
	for i, b := range blobs[:last+1] {
 | 
						|
		if b == nil || bytes.Equal(b, nullJSON) {
 | 
						|
			// a null object is in the list: skip it
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if len(b) > 0 && opening == 0 { // is this an array or an object?
 | 
						|
			opening, closing = b[0], closers[b[0]]
 | 
						|
		}
 | 
						|
 | 
						|
		if opening != '{' && opening != '[' {
 | 
						|
			continue // don't know how to concatenate non container objects
 | 
						|
		}
 | 
						|
 | 
						|
		if len(b) < 3 { // yep empty but also the last one, so closing this thing
 | 
						|
			if i == last && a > 0 {
 | 
						|
				if err := buf.WriteByte(closing); err != nil {
 | 
						|
					log.Println(err)
 | 
						|
				}
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		idx = 0
 | 
						|
		if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
 | 
						|
			if err := buf.WriteByte(comma); err != nil {
 | 
						|
				log.Println(err)
 | 
						|
			}
 | 
						|
			idx = 1 // this is not the first or the last so we want to drop the leading bracket
 | 
						|
		}
 | 
						|
 | 
						|
		if i != last { // not the last one, strip brackets
 | 
						|
			if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
 | 
						|
				log.Println(err)
 | 
						|
			}
 | 
						|
		} else { // last one, strip only the leading bracket
 | 
						|
			if _, err := buf.Write(b[idx:]); err != nil {
 | 
						|
				log.Println(err)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		a++
 | 
						|
	}
 | 
						|
	// somehow it ended up being empty, so provide a default value
 | 
						|
	if buf.Len() == 0 {
 | 
						|
		if err := buf.WriteByte(opening); err != nil {
 | 
						|
			log.Println(err)
 | 
						|
		}
 | 
						|
		if err := buf.WriteByte(closing); err != nil {
 | 
						|
			log.Println(err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return buf.Bytes()
 | 
						|
}
 | 
						|
 | 
						|
// ToDynamicJSON turns an object into a properly JSON typed structure
 | 
						|
func ToDynamicJSON(data interface{}) interface{} {
 | 
						|
	// TODO: convert straight to a json typed map (mergo + iterate?)
 | 
						|
	b, err := json.Marshal(data)
 | 
						|
	if err != nil {
 | 
						|
		log.Println(err)
 | 
						|
	}
 | 
						|
	var res interface{}
 | 
						|
	if err := json.Unmarshal(b, &res); err != nil {
 | 
						|
		log.Println(err)
 | 
						|
	}
 | 
						|
	return res
 | 
						|
}
 | 
						|
 | 
						|
// FromDynamicJSON turns an object into a properly JSON typed structure
 | 
						|
func FromDynamicJSON(data, target interface{}) error {
 | 
						|
	b, err := json.Marshal(data)
 | 
						|
	if err != nil {
 | 
						|
		log.Println(err)
 | 
						|
	}
 | 
						|
	return json.Unmarshal(b, target)
 | 
						|
}
 | 
						|
 | 
						|
// NameProvider represents an object capable of translating from go property names
 | 
						|
// to json property names
 | 
						|
// This type is thread-safe.
 | 
						|
type NameProvider struct {
 | 
						|
	lock  *sync.Mutex
 | 
						|
	index map[reflect.Type]nameIndex
 | 
						|
}
 | 
						|
 | 
						|
type nameIndex struct {
 | 
						|
	jsonNames map[string]string
 | 
						|
	goNames   map[string]string
 | 
						|
}
 | 
						|
 | 
						|
// NewNameProvider creates a new name provider
 | 
						|
func NewNameProvider() *NameProvider {
 | 
						|
	return &NameProvider{
 | 
						|
		lock:  &sync.Mutex{},
 | 
						|
		index: make(map[reflect.Type]nameIndex),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
 | 
						|
	for i := 0; i < tpe.NumField(); i++ {
 | 
						|
		targetDes := tpe.Field(i)
 | 
						|
 | 
						|
		if targetDes.PkgPath != "" { // unexported
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if targetDes.Anonymous { // walk embedded structures tree down first
 | 
						|
			buildnameIndex(targetDes.Type, idx, reverseIdx)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if tag := targetDes.Tag.Get("json"); tag != "" {
 | 
						|
 | 
						|
			parts := strings.Split(tag, ",")
 | 
						|
			if len(parts) == 0 {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			nm := parts[0]
 | 
						|
			if nm == "-" {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			if nm == "" { // empty string means we want to use the Go name
 | 
						|
				nm = targetDes.Name
 | 
						|
			}
 | 
						|
 | 
						|
			idx[nm] = targetDes.Name
 | 
						|
			reverseIdx[targetDes.Name] = nm
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func newNameIndex(tpe reflect.Type) nameIndex {
 | 
						|
	var idx = make(map[string]string, tpe.NumField())
 | 
						|
	var reverseIdx = make(map[string]string, tpe.NumField())
 | 
						|
 | 
						|
	buildnameIndex(tpe, idx, reverseIdx)
 | 
						|
	return nameIndex{jsonNames: idx, goNames: reverseIdx}
 | 
						|
}
 | 
						|
 | 
						|
// GetJSONNames gets all the json property names for a type
 | 
						|
func (n *NameProvider) GetJSONNames(subject interface{}) []string {
 | 
						|
	n.lock.Lock()
 | 
						|
	defer n.lock.Unlock()
 | 
						|
	tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
 | 
						|
	names, ok := n.index[tpe]
 | 
						|
	if !ok {
 | 
						|
		names = n.makeNameIndex(tpe)
 | 
						|
	}
 | 
						|
 | 
						|
	res := make([]string, 0, len(names.jsonNames))
 | 
						|
	for k := range names.jsonNames {
 | 
						|
		res = append(res, k)
 | 
						|
	}
 | 
						|
	return res
 | 
						|
}
 | 
						|
 | 
						|
// GetJSONName gets the json name for a go property name
 | 
						|
func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
 | 
						|
	tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
 | 
						|
	return n.GetJSONNameForType(tpe, name)
 | 
						|
}
 | 
						|
 | 
						|
// GetJSONNameForType gets the json name for a go property name on a given type
 | 
						|
func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
 | 
						|
	n.lock.Lock()
 | 
						|
	defer n.lock.Unlock()
 | 
						|
	names, ok := n.index[tpe]
 | 
						|
	if !ok {
 | 
						|
		names = n.makeNameIndex(tpe)
 | 
						|
	}
 | 
						|
	nme, ok := names.goNames[name]
 | 
						|
	return nme, ok
 | 
						|
}
 | 
						|
 | 
						|
func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
 | 
						|
	names := newNameIndex(tpe)
 | 
						|
	n.index[tpe] = names
 | 
						|
	return names
 | 
						|
}
 | 
						|
 | 
						|
// GetGoName gets the go name for a json property name
 | 
						|
func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
 | 
						|
	tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
 | 
						|
	return n.GetGoNameForType(tpe, name)
 | 
						|
}
 | 
						|
 | 
						|
// GetGoNameForType gets the go name for a given type for a json property name
 | 
						|
func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
 | 
						|
	n.lock.Lock()
 | 
						|
	defer n.lock.Unlock()
 | 
						|
	names, ok := n.index[tpe]
 | 
						|
	if !ok {
 | 
						|
		names = n.makeNameIndex(tpe)
 | 
						|
	}
 | 
						|
	nme, ok := names.jsonNames[name]
 | 
						|
	return nme, ok
 | 
						|
}
 |