// ConvertWorkItem is responsible for converting given WorkItem model object into a // response resource object by jsonapi.org specifications func ConvertWorkItem(request *goa.RequestData, wi *app.WorkItem, additional ...WorkItemConvertFunc) *app.WorkItem2 { // construct default values from input WI selfURL := rest.AbsoluteURL(request, app.WorkitemHref(wi.ID)) sourceLinkTypesURL := rest.AbsoluteURL(request, app.WorkitemtypeHref(wi.Type)+sourceLinkTypesRouteEnd) targetLinkTypesURL := rest.AbsoluteURL(request, app.WorkitemtypeHref(wi.Type)+targetLinkTypesRouteEnd) op := &app.WorkItem2{ ID: &wi.ID, Type: APIStringTypeWorkItem, Attributes: map[string]interface{}{ "version": wi.Version, }, Relationships: &app.WorkItemRelationships{ BaseType: &app.RelationBaseType{ Data: &app.BaseTypeData{ ID: wi.Type, Type: APIStringTypeWorkItemType, }, }, }, Links: &app.GenericLinksForWorkItem{ Self: &selfURL, SourceLinkTypes: &sourceLinkTypesURL, TargetLinkTypes: &targetLinkTypesURL, }, } // Move fields into Relationships or Attributes as needed // TODO: Loop based on WorKItemType and match against Field.Type instead of directly to field value for name, val := range wi.Fields { switch name { case workitem.SystemAssignees: if val != nil { valArr := val.([]interface{}) op.Relationships.Assignees = &app.RelationGenericList{ Data: ConvertUsersSimple(request, valArr), } } case workitem.SystemCreator: if val != nil { valStr := val.(string) op.Relationships.Creator = &app.RelationGeneric{ Data: ConvertUserSimple(request, valStr), } } case workitem.SystemIteration: if val != nil { valStr := val.(string) op.Relationships.Iteration = &app.RelationGeneric{ Data: ConvertIterationSimple(request, valStr), } } case workitem.SystemArea: if val != nil { valStr := val.(string) op.Relationships.Area = &app.RelationGeneric{ Data: ConvertAreaSimple(request, valStr), } } case workitem.SystemTitle: // 'HTML escape' the title to prevent script injection op.Attributes[name] = html.EscapeString(val.(string)) case workitem.SystemDescription: description := rendering.NewMarkupContentFromValue(val) if description != nil { op.Attributes[name] = (*description).Content op.Attributes[workitem.SystemDescriptionMarkup] = (*description).Markup // let's include the rendered description while 'HTML escaping' it to prevent script injection op.Attributes[workitem.SystemDescriptionRendered] = rendering.RenderMarkupToHTML(html.EscapeString((*description).Content), (*description).Markup) } default: op.Attributes[name] = val } } if op.Relationships.Assignees == nil { op.Relationships.Assignees = &app.RelationGenericList{Data: nil} } if op.Relationships.Iteration == nil { op.Relationships.Iteration = &app.RelationGeneric{Data: nil} } if op.Relationships.Area == nil { op.Relationships.Area = &app.RelationGeneric{Data: nil} } // Always include Comments Link, but optionally use WorkItemIncludeCommentsAndTotal WorkItemIncludeComments(request, wi, op) for _, add := range additional { add(request, wi, op) } return op }
// ConvertJSONAPIToWorkItem is responsible for converting given WorkItem model object into a // response resource object by jsonapi.org specifications func ConvertJSONAPIToWorkItem(appl application.Application, source app.WorkItem2, target *app.WorkItem) error { // construct default values from input WI version, err := getVersion(source.Attributes["version"]) if err != nil { return err } target.Version = version if source.Relationships != nil && source.Relationships.Assignees != nil { if source.Relationships.Assignees.Data == nil { delete(target.Fields, workitem.SystemAssignees) } else { var ids []string for _, d := range source.Relationships.Assignees.Data { assigneeUUID, err := uuid.FromString(*d.ID) if err != nil { return errors.NewBadParameterError("data.relationships.assignees.data.id", *d.ID) } if ok := appl.Identities().IsValid(context.Background(), assigneeUUID); !ok { return errors.NewBadParameterError("data.relationships.assignees.data.id", *d.ID) } ids = append(ids, assigneeUUID.String()) } target.Fields[workitem.SystemAssignees] = ids } } if source.Relationships != nil && source.Relationships.Iteration != nil { if source.Relationships.Iteration.Data == nil { delete(target.Fields, workitem.SystemIteration) } else { d := source.Relationships.Iteration.Data iterationUUID, err := uuid.FromString(*d.ID) if err != nil { return errors.NewBadParameterError("data.relationships.iteration.data.id", *d.ID) } if _, err = appl.Iterations().Load(context.Background(), iterationUUID); err != nil { return errors.NewBadParameterError("data.relationships.iteration.data.id", *d.ID) } target.Fields[workitem.SystemIteration] = iterationUUID.String() } } if source.Relationships != nil && source.Relationships.Area != nil { if source.Relationships.Area.Data == nil { delete(target.Fields, workitem.SystemArea) } else { d := source.Relationships.Area.Data areaUUID, err := uuid.FromString(*d.ID) if err != nil { return errors.NewBadParameterError("data.relationships.area.data.id", *d.ID) } if _, err = appl.Areas().Load(context.Background(), areaUUID); err != nil { return errors.NewBadParameterError("data.relationships.area.data.id", *d.ID) } target.Fields[workitem.SystemArea] = areaUUID.String() } } if source.Relationships != nil && source.Relationships.BaseType != nil { if source.Relationships.BaseType.Data != nil { target.Type = source.Relationships.BaseType.Data.ID } } for key, val := range source.Attributes { // convert legacy description to markup content if key == workitem.SystemDescription { if m := rendering.NewMarkupContentFromValue(val); m != nil { target.Fields[key] = *m } } else { target.Fields[key] = val } } if description, ok := target.Fields[workitem.SystemDescription].(rendering.MarkupContent); ok { // verify the description markup if !rendering.IsMarkupSupported(description.Markup) { return errors.NewBadParameterError("data.relationships.attributes[system.description].markup", description.Markup) } } return nil }