1
0
mirror of https://github.com/rancher/steve.git synced 2025-04-27 02:51:10 +00:00
steve/pkg/schemaserver/writer/encoding.go
Darren Shepherd 8b42d0aff8 Refactor
2020-01-30 22:37:59 -07:00

125 lines
3.4 KiB
Go

package writer
import (
"io"
"net/http"
"github.com/rancher/steve/pkg/schemaserver/types"
)
type EncodingResponseWriter struct {
ContentType string
Encoder func(io.Writer, interface{}) error
}
func (j *EncodingResponseWriter) start(apiOp *types.APIRequest, code int) {
AddCommonResponseHeader(apiOp)
apiOp.Response.Header().Set("content-type", j.ContentType)
apiOp.Response.WriteHeader(code)
}
func (j *EncodingResponseWriter) Write(apiOp *types.APIRequest, code int, obj types.APIObject) {
j.start(apiOp, code)
j.Body(apiOp, apiOp.Response, obj)
}
func (j *EncodingResponseWriter) WriteList(apiOp *types.APIRequest, code int, list types.APIObjectList) {
j.start(apiOp, code)
j.BodyList(apiOp, apiOp.Response, list)
}
func (j *EncodingResponseWriter) Body(apiOp *types.APIRequest, writer io.Writer, obj types.APIObject) error {
return j.Encoder(writer, j.convert(apiOp, obj))
}
func (j *EncodingResponseWriter) BodyList(apiOp *types.APIRequest, writer io.Writer, list types.APIObjectList) error {
return j.Encoder(writer, j.convertList(apiOp, list))
}
func (j *EncodingResponseWriter) convertList(apiOp *types.APIRequest, input types.APIObjectList) *types.GenericCollection {
collection := newCollection(apiOp, input)
for _, value := range input.Objects {
converted := j.convert(apiOp, value)
collection.Data = append(collection.Data, converted)
}
if apiOp.Schema.CollectionFormatter != nil {
apiOp.Schema.CollectionFormatter(apiOp, collection)
}
return collection
}
func (j *EncodingResponseWriter) convert(context *types.APIRequest, input types.APIObject) *types.RawResource {
schema := context.Schemas.LookupSchema(input.Type)
if schema == nil {
schema = context.Schema
}
if schema == nil {
return nil
}
rawResource := &types.RawResource{
ID: input.ID,
Type: schema.ID,
Schema: schema,
Links: map[string]string{},
Actions: map[string]string{},
ActionLinks: context.Request.Header.Get("X-API-Action-Links") != "",
APIObject: input,
}
j.addLinks(schema, context, input, rawResource)
if schema.Formatter != nil {
schema.Formatter(context, rawResource)
}
return rawResource
}
func (j *EncodingResponseWriter) addLinks(schema *types.APISchema, context *types.APIRequest, input types.APIObject, rawResource *types.RawResource) {
if rawResource.ID == "" {
return
}
self := context.URLBuilder.ResourceLink(rawResource.Schema, rawResource.ID)
if _, ok := rawResource.Links["self"]; !ok {
rawResource.Links["self"] = self
}
if _, ok := rawResource.Links["update"]; !ok {
if context.AccessControl.CanUpdate(context, input, schema) == nil {
rawResource.Links["update"] = self
}
}
if _, ok := rawResource.Links["remove"]; !ok {
if context.AccessControl.CanDelete(context, input, schema) == nil {
rawResource.Links["remove"] = self
}
}
}
func newCollection(apiOp *types.APIRequest, list types.APIObjectList) *types.GenericCollection {
result := &types.GenericCollection{
Collection: types.Collection{
Type: "collection",
ResourceType: apiOp.Type,
CreateTypes: map[string]string{},
Links: map[string]string{
"self": apiOp.URLBuilder.Current(),
},
Actions: map[string]string{},
Continue: list.Continue,
Revision: list.Revision,
},
}
if apiOp.Method == http.MethodGet {
if apiOp.AccessControl.CanCreate(apiOp, apiOp.Schema) == nil {
result.CreateTypes[apiOp.Schema.ID] = apiOp.URLBuilder.Collection(apiOp.Schema)
}
}
return result
}