// Update does PATCH comment func (c *CommentsController) Update(ctx *app.UpdateCommentsContext) error { identity, err := login.ContextIdentity(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { cm, err := appl.Comments().Load(ctx.Context, ctx.CommentID) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } if identity != cm.CreatedBy.String() { // need to use the goa.NewErrorClass() func as there is no native support for 403 in goa // and it is not planned to be supported yet: https://github.com/goadesign/goa/pull/1030 return jsonapi.JSONErrorResponse(ctx, goa.NewErrorClass("forbidden", 403)("User is not the comment author")) } cm.Body = *ctx.Payload.Data.Attributes.Body cm.Markup = rendering.NilSafeGetMarkup(ctx.Payload.Data.Attributes.Markup) cm, err = appl.Comments().Save(ctx.Context, cm) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } res := &app.CommentSingle{ Data: ConvertComment(ctx.RequestData, cm, CommentIncludeParentWorkItem()), } return ctx.OK(res) }) }
// Refresh obtain a new access token using the refresh token. func (c *LoginController) Refresh(ctx *app.RefreshLoginContext) error { refreshToken := ctx.Payload.RefreshToken if refreshToken == nil { return jsonapi.JSONErrorResponse(ctx, errors.NewBadParameterError("refresh_token", nil).Expected("not nil")) } client := &http.Client{Timeout: 10 * time.Second} res, err := client.PostForm(configuration.GetKeycloakEndpointToken(), url.Values{ "client_id": {configuration.GetKeycloakClientID()}, "client_secret": {configuration.GetKeycloakSecret()}, "refresh_token": {*refreshToken}, "grant_type": {"refresh_token"}, }) if err != nil { return jsonapi.JSONErrorResponse(ctx, errors.NewInternalError("Error when obtaining token "+err.Error())) } switch res.StatusCode { case 200: // OK case 401: return jsonapi.JSONErrorResponse(ctx, errors.NewUnauthorizedError(res.Status+" "+readBody(res.Body))) case 400: return jsonapi.JSONErrorResponse(ctx, errors.NewBadParameterError(readBody(res.Body), nil)) default: return jsonapi.JSONErrorResponse(ctx, errors.NewInternalError(res.Status+" "+readBody(res.Body))) } token, err := readToken(res, ctx) if err != nil { return err } return ctx.OK(&app.AuthToken{Token: token}) }
// Update does PATCH workitem func (c *WorkitemController) Update(ctx *app.UpdateWorkitemContext) error { return application.Transactional(c.db, func(appl application.Application) error { if ctx.Payload == nil || ctx.Payload.Data == nil || ctx.Payload.Data.ID == nil { return jsonapi.JSONErrorResponse(ctx, errors.NewBadParameterError("missing data.ID element in request", nil)) } wi, err := appl.WorkItems().Load(ctx, *ctx.Payload.Data.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, errs.Wrap(err, fmt.Sprintf("Failed to load work item with id %v", *ctx.Payload.Data.ID))) } // Type changes of WI are not allowed which is why we overwrite it the // type with the old one after the WI has been converted. oldType := wi.Type err = ConvertJSONAPIToWorkItem(appl, *ctx.Payload.Data, wi) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } wi.Type = oldType wi, err = appl.WorkItems().Save(ctx, *wi) if err != nil { return jsonapi.JSONErrorResponse(ctx, errs.Wrap(err, "Error updating work item")) } wi2 := ConvertWorkItem(ctx.RequestData, wi) resp := &app.WorkItem2Single{ Data: wi2, Links: &app.WorkItemLinks{ Self: buildAbsoluteURL(ctx.RequestData), }, } return ctx.OK(resp) }) }
// Create runs the create action. func (c *SpaceController) Create(ctx *app.CreateSpaceContext) error { _, err := login.ContextIdentity(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } err = validateCreateSpace(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } return application.Transactional(c.db, func(appl application.Application) error { reqSpace := ctx.Payload.Data newSpace := space.Space{ Name: *reqSpace.Attributes.Name, } if reqSpace.Attributes.Description != nil { newSpace.Description = *reqSpace.Attributes.Description } space, err := appl.Spaces().Create(ctx, &newSpace) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } res := &app.SpaceSingle{ Data: ConvertSpace(ctx.RequestData, space), } ctx.ResponseData.Header().Set("Location", rest.AbsoluteURL(ctx.RequestData, app.SpaceHref(res.Data.ID))) return ctx.Created(res) }) }
// List runs the list action. func (c *SpaceIterationsController) List(ctx *app.ListSpaceIterationsContext) error { spaceID, err := uuid.FromString(ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { _, err = appl.Spaces().Load(ctx, spaceID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } iterations, err := appl.Iterations().List(ctx, spaceID) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } // fetch extra information(counts of WI in each iteration of the space) to be added in response wiCounts, err := appl.WorkItems().GetCountsPerIteration(ctx, spaceID) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } res := &app.IterationList{} res.Data = ConvertIterations(ctx.RequestData, iterations, UpdateIterationsWithCounts(wiCounts)) return ctx.OK(res) }) }
// Delete does DELETE workitem func (c *WorkitemController) Delete(ctx *app.DeleteWorkitemContext) error { return application.Transactional(c.db, func(appl application.Application) error { err := appl.WorkItems().Delete(ctx, ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, errs.Wrapf(err, "error deleting work item %s", ctx.ID)) } if err := appl.WorkItemLinks().DeleteRelatedLinks(ctx, ctx.ID); err != nil { return jsonapi.JSONErrorResponse(ctx, errs.Wrapf(err, "failed to delete work item links related to work item %s", ctx.ID)) } return ctx.OK([]byte{}) }) }
// Update runs the update action. func (c *IterationController) Update(ctx *app.UpdateIterationContext) error { _, err := login.ContextIdentity(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } id, err := uuid.FromString(ctx.IterationID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { itr, err := appl.Iterations().Load(ctx.Context, id) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } if ctx.Payload.Data.Attributes.Name != nil { itr.Name = *ctx.Payload.Data.Attributes.Name } if ctx.Payload.Data.Attributes.StartAt != nil { itr.StartAt = ctx.Payload.Data.Attributes.StartAt } if ctx.Payload.Data.Attributes.EndAt != nil { itr.EndAt = ctx.Payload.Data.Attributes.EndAt } if ctx.Payload.Data.Attributes.Description != nil { itr.Description = ctx.Payload.Data.Attributes.Description } if ctx.Payload.Data.Attributes.State != nil { if *ctx.Payload.Data.Attributes.State == iteration.IterationStateStart { res, err := appl.Iterations().CanStartIteration(ctx, itr) if res == false && err != nil { return jsonapi.JSONErrorResponse(ctx, err) } } itr.State = *ctx.Payload.Data.Attributes.State } itr, err = appl.Iterations().Save(ctx.Context, *itr) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } response := app.IterationSingle{ Data: ConvertIteration(ctx.RequestData, itr), } return ctx.OK(&response) }) }
// Show returns the authorized user based on the provided Token func (c *UserController) Show(ctx *app.ShowUserContext) error { id, err := c.tokenManager.Locate(ctx) if err != nil { jerrors, _ := jsonapi.ErrorToJSONAPIErrors(goa.ErrBadRequest(err.Error())) return ctx.BadRequest(jerrors) } return application.Transactional(c.db, func(appl application.Application) error { identity, err := appl.Identities().Load(ctx, id) if err != nil || identity == nil { log.Error(ctx, map[string]interface{}{ "identityID": id, }, "auth token containers id %s of unknown Identity", id) jerrors, _ := jsonapi.ErrorToJSONAPIErrors(goa.ErrUnauthorized(fmt.Sprintf("Auth token contains id %s of unknown Identity\n", id))) return ctx.Unauthorized(jerrors) } var user *account.User userID := identity.UserID if userID.Valid { user, err = appl.Users().Load(ctx.Context, userID.UUID) if err != nil { return jsonapi.JSONErrorResponse(ctx, errors.Wrap(err, fmt.Sprintf("Can't load user with id %s", userID.UUID))) } } return ctx.OK(ConvertUser(ctx.RequestData, identity, user)) }) }
// Show runs the show action. func (c *AreaController) Show(ctx *app.ShowAreaContext) error { id, err := uuid.FromString(ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { a, err := appl.Areas().Load(ctx, id) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } res := &app.AreaSingle{} res.Data = ConvertArea(appl, ctx.RequestData, a, addResolvedPath) return ctx.OK(res) }) }
// Show runs the show action. func (c *WorkitemtypeController) Show(ctx *app.ShowWorkitemtypeContext) error { return application.Transactional(c.db, func(appl application.Application) error { res, err := appl.WorkItemTypes().Load(ctx.Context, ctx.Name) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } return ctx.OK(res) }) }
// Delete runs the delete action. func (c *SpaceController) Delete(ctx *app.DeleteSpaceContext) error { _, err := login.ContextIdentity(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } id, err := satoriuuid.FromString(ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { err = appl.Spaces().Delete(ctx.Context, id) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } return ctx.OK([]byte{}) }) }
// Spaces runs the space search action. func (c *SearchController) Spaces(ctx *app.SpacesSearchContext) error { q := ctx.Q if q == "" { return jsonapi.JSONErrorResponse(ctx, goa.ErrBadRequest(fmt.Errorf("Empty search query not allowed"))) } else if q == "*" { q = "" // Allow empty query if * specified } var result []*space.Space var count int var err error offset, limit := computePagingLimts(ctx.PageOffset, ctx.PageLimit) return application.Transactional(c.db, func(appl application.Application) error { var resultCount uint64 result, resultCount, err = appl.Spaces().Search(ctx, &q, &offset, &limit) count = int(resultCount) if err != nil { cause := errs.Cause(err) switch cause.(type) { case errors.BadParameterError: return jsonapi.JSONErrorResponse(ctx, goa.ErrBadRequest(fmt.Sprintf("Error listing spaces: %s", err.Error()))) default: log.Error(ctx, map[string]interface{}{ "query": q, "offset": offset, "limit": limit, "err": err, }, "unable to list spaces") return jsonapi.JSONErrorResponse(ctx, goa.ErrInternal(err.Error())) } } response := app.SearchSpaceList{ Links: &app.PagingLinks{}, Meta: &app.SpaceListMeta{TotalCount: count}, Data: ConvertSpaces(ctx.RequestData, result), } setPagingLinks(response.Links, buildAbsoluteURL(ctx.RequestData), len(result), offset, limit, count, "q="+q) return ctx.OK(&response) }) }
// CreateChild runs the create-child action. func (c *AreaController) CreateChild(ctx *app.CreateChildAreaContext) error { _, err := login.ContextIdentity(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } parentID, err := uuid.FromString(ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { parent, err := appl.Areas().Load(ctx, parentID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } reqArea := ctx.Payload.Data if reqArea.Attributes.Name == nil { return jsonapi.JSONErrorResponse(ctx, errors.NewBadParameterError("data.attributes.name", nil).Expected("not nil")) } childPath := area.ConvertToLtreeFormat(parentID.String()) if parent.Path != "" { childPath = parent.Path + pathSepInDatabase + childPath } newArea := area.Area{ SpaceID: parent.SpaceID, Path: childPath, Name: *reqArea.Attributes.Name, } err = appl.Areas().Create(ctx, &newArea) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } res := &app.AreaSingle{ Data: ConvertArea(appl, ctx.RequestData, &newArea, addResolvedPath), } ctx.ResponseData.Header().Set("Location", rest.AbsoluteURL(ctx.RequestData, app.AreaHref(res.Data.ID))) return ctx.Created(res) }) }
// Generate obtain the access token from Keycloak for the test user func (c *LoginController) Generate(ctx *app.GenerateLoginContext) error { if !configuration.IsPostgresDeveloperModeEnabled() { log.Error(ctx, map[string]interface{}{ "method": "Generate", }, "Postgres developer mode not enabled") jerrors, _ := jsonapi.ErrorToJSONAPIErrors(goa.ErrUnauthorized("Postgres developer mode not enabled")) return ctx.Unauthorized(jerrors) } var scopes []account.Identity scopes = append(scopes, test.TestIdentity) scopes = append(scopes, test.TestObserverIdentity) client := &http.Client{Timeout: 10 * time.Second} username := configuration.GetKeycloakTestUserName() res, err := client.PostForm(configuration.GetKeycloakEndpointToken(), url.Values{ "client_id": {configuration.GetKeycloakClientID()}, "client_secret": {configuration.GetKeycloakSecret()}, "username": {username}, "password": {configuration.GetKeycloakTestUserSecret()}, "grant_type": {"password"}, }) if err != nil { return jsonapi.JSONErrorResponse(ctx, errors.NewInternalError("error when obtaining token "+err.Error())) } token, err := readToken(res, ctx) if err != nil { log.Error(ctx, map[string]interface{}{ "tokenEndpoint": res, "err": err, }, "Error when unmarshal json with access token") return jsonapi.JSONErrorResponse(ctx, e.Wrap(err, "Error when unmarshal json with access token")) } var tokens app.AuthTokenCollection tokens = append(tokens, &app.AuthToken{Token: token}) // Creates the testuser user and identity if they don't yet exist c.auth.CreateKeycloakUser(*token.AccessToken, ctx) return ctx.OK(tokens) }
// Show runs the show action. func (c *SpaceController) Show(ctx *app.ShowSpaceContext) error { id, err := satoriuuid.FromString(ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { s, err := appl.Spaces().Load(ctx.Context, id) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } resp := app.SpaceSingle{ Data: ConvertSpace(ctx.RequestData, s), } return ctx.OK(&resp) }) }
// List runs the list action. // Prev and Next links will be present only when there actually IS a next or previous page. // Last will always be present. Total Item count needs to be computed from the "Last" link. func (c *WorkitemController) List(ctx *app.ListWorkitemContext) error { var additionalQuery []string exp, err := query.Parse(ctx.Filter) if err != nil { return jsonapi.JSONErrorResponse(ctx, errors.NewBadParameterError("could not parse filter", err)) } if ctx.FilterAssignee != nil { assignee := ctx.FilterAssignee exp = criteria.And(exp, criteria.Equals(criteria.Field("system.assignees"), criteria.Literal([]string{*assignee}))) additionalQuery = append(additionalQuery, "filter[assignee]="+*assignee) } if ctx.FilterIteration != nil { iteration := ctx.FilterIteration exp = criteria.And(exp, criteria.Equals(criteria.Field(workitem.SystemIteration), criteria.Literal(string(*iteration)))) additionalQuery = append(additionalQuery, "filter[iteration]="+*iteration) } if ctx.FilterWorkitemtype != nil { wit := ctx.FilterWorkitemtype exp = criteria.And(exp, criteria.Equals(criteria.Field("Type"), criteria.Literal([]string{*wit}))) additionalQuery = append(additionalQuery, "filter[workitemtype]="+*wit) } if ctx.FilterArea != nil { area := ctx.FilterArea exp = criteria.And(exp, criteria.Equals(criteria.Field(workitem.SystemArea), criteria.Literal(string(*area)))) additionalQuery = append(additionalQuery, "filter[area]="+*area) } offset, limit := computePagingLimts(ctx.PageOffset, ctx.PageLimit) return application.Transactional(c.db, func(tx application.Application) error { result, tc, err := tx.WorkItems().List(ctx.Context, exp, &offset, &limit) count := int(tc) if err != nil { return jsonapi.JSONErrorResponse(ctx, errs.Wrap(err, "Error listing work items")) } response := app.WorkItem2List{ Links: &app.PagingLinks{}, Meta: &app.WorkItemListResponseMeta{TotalCount: count}, Data: ConvertWorkItems(ctx.RequestData, result), } setPagingLinks(response.Links, buildAbsoluteURL(ctx.RequestData), len(result), offset, limit, count, additionalQuery...) return ctx.OK(&response) }) }
// CreateChild runs the create-child action. func (c *IterationController) CreateChild(ctx *app.CreateChildIterationContext) error { _, err := login.ContextIdentity(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } parentID, err := uuid.FromString(ctx.IterationID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { parent, err := appl.Iterations().Load(ctx, parentID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } reqIter := ctx.Payload.Data if reqIter.Attributes.Name == nil { return jsonapi.JSONErrorResponse(ctx, errors.NewBadParameterError("data.attributes.name", nil).Expected("not nil")) } newItr := iteration.Iteration{ SpaceID: parent.SpaceID, ParentID: parentID, Name: *reqIter.Attributes.Name, StartAt: reqIter.Attributes.StartAt, EndAt: reqIter.Attributes.EndAt, } err = appl.Iterations().Create(ctx, &newItr) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } res := &app.IterationSingle{ Data: ConvertIteration(ctx.RequestData, &newItr), } ctx.ResponseData.Header().Set("Location", rest.AbsoluteURL(ctx.RequestData, app.IterationHref(res.Data.ID))) return ctx.Created(res) }) }
// Show runs the show action. func (c *IterationController) Show(ctx *app.ShowIterationContext) error { id, err := uuid.FromString(ctx.IterationID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { c, err := appl.Iterations().Load(ctx, id) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } res := &app.IterationSingle{} res.Data = ConvertIteration( ctx.RequestData, c) return ctx.OK(res) }) }
// Update runs the update action. func (c *SpaceController) Update(ctx *app.UpdateSpaceContext) error { _, err := login.ContextIdentity(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } id, err := satoriuuid.FromString(ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } err = validateUpdateSpace(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } return application.Transactional(c.db, func(appl application.Application) error { s, err := appl.Spaces().Load(ctx.Context, id) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } s.Version = *ctx.Payload.Data.Attributes.Version if ctx.Payload.Data.Attributes.Name != nil { s.Name = *ctx.Payload.Data.Attributes.Name } if ctx.Payload.Data.Attributes.Description != nil { s.Description = *ctx.Payload.Data.Attributes.Description } s, err = appl.Spaces().Save(ctx.Context, s) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } response := app.SpaceSingle{ Data: ConvertSpace(ctx.RequestData, s), } return ctx.OK(&response) }) }
// ListSourceLinkTypes runs the list-source-link-types action. func (c *WorkitemtypeController) ListSourceLinkTypes(ctx *app.ListSourceLinkTypesWorkitemtypeContext) error { return application.Transactional(c.db, func(appl application.Application) error { // Test that work item type exists _, err := appl.WorkItemTypes().Load(ctx.Context, ctx.Name) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } // Fetch all link types where this work item type can be used in the // source of the link res, err := appl.WorkItemLinkTypes().ListSourceLinkTypes(ctx.Context, ctx.Name) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } // Enrich link types linkCtx := newWorkItemLinkContext(ctx.Context, appl, c.db, ctx.RequestData, ctx.ResponseData, app.WorkItemLinkTypeHref) err = enrichLinkTypeList(linkCtx, res) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } return ctx.OK(res) }) }
// Create does POST workitem func (c *WorkitemController) Create(ctx *app.CreateWorkitemContext) error { currentUser, err := login.ContextIdentity(ctx) if err != nil { jerrors, _ := jsonapi.ErrorToJSONAPIErrors(goa.ErrUnauthorized(err.Error())) return ctx.Unauthorized(jerrors) } var wit *string if ctx.Payload.Data != nil && ctx.Payload.Data.Relationships != nil && ctx.Payload.Data.Relationships.BaseType != nil && ctx.Payload.Data.Relationships.BaseType.Data != nil { wit = &ctx.Payload.Data.Relationships.BaseType.Data.ID } if wit == nil { // TODO Figure out path source etc. Should be a required relation return jsonapi.JSONErrorResponse(ctx, errors.NewBadParameterError("Data.Relationships.BaseType.Data.ID", err)) } wi := app.WorkItem{ Fields: make(map[string]interface{}), } return application.Transactional(c.db, func(appl application.Application) error { err := ConvertJSONAPIToWorkItem(appl, *ctx.Payload.Data, &wi) if err != nil { return jsonapi.JSONErrorResponse(ctx, errs.Wrap(err, fmt.Sprintf("Error creating work item"))) } wi, err := appl.WorkItems().Create(ctx, *wit, wi.Fields, currentUser) if err != nil { return jsonapi.JSONErrorResponse(ctx, errs.Wrap(err, fmt.Sprintf("Error creating work item"))) } wi2 := ConvertWorkItem(ctx.RequestData, wi) resp := &app.WorkItem2Single{ Data: wi2, Links: &app.WorkItemLinks{ Self: buildAbsoluteURL(ctx.RequestData), }, } ctx.ResponseData.Header().Set("Location", app.WorkitemHref(wi2.ID)) return ctx.Created(resp) }) }
func readToken(res *http.Response, ctx jsonapi.InternalServerError) (*app.TokenData, error) { // Read the json out of the response body buf := new(bytes.Buffer) io.Copy(buf, res.Body) res.Body.Close() jsonString := strings.TrimSpace(buf.String()) var token app.TokenData err := json.Unmarshal([]byte(jsonString), &token) if err != nil { return nil, jsonapi.JSONErrorResponse(ctx, errors.NewInternalError(fmt.Sprintf("error when unmarshal json with access token %s ", jsonString)+err.Error())) } return &token, nil }
// Show does GET workitem func (c *WorkitemController) Show(ctx *app.ShowWorkitemContext) error { return application.Transactional(c.db, func(appl application.Application) error { comments := WorkItemIncludeCommentsAndTotal(ctx, c.db, ctx.ID) wi, err := appl.WorkItems().Load(ctx, ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, errs.Wrap(err, fmt.Sprintf("Fail to load work item with id %v", ctx.ID))) } wi2 := ConvertWorkItem(ctx.RequestData, wi, comments) resp := &app.WorkItem2Single{ Data: wi2, } return ctx.OK(resp) }) }
// Relations runs the relation action. // TODO: Should only return Resource Identifier Objects, not complete object (See List) func (c *WorkItemCommentsController) Relations(ctx *app.RelationsWorkItemCommentsContext) error { offset, limit := computePagingLimts(ctx.PageOffset, ctx.PageLimit) return application.Transactional(c.db, func(appl application.Application) error { wi, err := appl.WorkItems().Load(ctx, ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } comments, tc, err := appl.Comments().List(ctx, ctx.ID, &offset, &limit) count := int(tc) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrInternal(err.Error())) } _ = wi _ = comments res := &app.CommentRelationshipList{} res.Meta = &app.CommentListMeta{TotalCount: count} res.Data = ConvertCommentsResourceID(ctx.RequestData, comments) res.Links = CreateCommentsRelationLinks(ctx.RequestData, wi) return ctx.OK(res) }) }
// Render runs the render action. func (c *RenderController) Render(ctx *app.RenderRenderContext) error { content := ctx.Payload.Data.Attributes.Content markup := ctx.Payload.Data.Attributes.Markup if !rendering.IsMarkupSupported(markup) { return jsonapi.JSONErrorResponse(ctx, errors.NewBadParameterError("Unsupported markup type", markup)) } htmlResult := rendering.RenderMarkupToHTML(content, markup) res := &app.MarkupRenderingSingle{Data: &app.MarkupRenderingData{ ID: uuid.NewV4().String(), Type: RenderingType, Attributes: &app.MarkupRenderingDataAttributes{ RenderedContent: htmlResult, }}} return ctx.OK(res) }
// Delete does DELETE comment func (c *CommentsController) Delete(ctx *app.DeleteCommentsContext) error { identity, err := login.ContextIdentity(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { cm, err := appl.Comments().Load(ctx.Context, ctx.CommentID) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } if identity != cm.CreatedBy.String() { // need to use the goa.NewErrorClass() func as there is no native support for 403 in goa // and it is not planned to be supported yet: https://github.com/goadesign/goa/pull/1030 return jsonapi.JSONErrorResponse(ctx, goa.NewErrorClass("forbidden", 403)("User is not the comment author")) } err = appl.Comments().Delete(ctx.Context, cm.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } return ctx.OK([]byte{}) }) }
// List runs the list action. func (c *SpaceAreasController) List(ctx *app.ListSpaceAreasContext) error { spaceID, err := uuid.FromString(ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } return application.Transactional(c.db, func(appl application.Application) error { _, err = appl.Spaces().Load(ctx, spaceID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } areas, err := appl.Areas().List(ctx, spaceID) if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } res := &app.AreaList{} res.Data = ConvertAreas(appl, ctx.RequestData, areas, addResolvedPath) return ctx.OK(res) }) }
// List runs the list action. func (c *UsersController) List(ctx *app.ListUsersContext) error { return application.Transactional(c.db, func(appl application.Application) error { var err error var users []*account.User var result *app.UserArray users, err = appl.Users().List(ctx.Context) if err == nil { result, err = LoadKeyCloakIdentities(appl, ctx.RequestData, users) if err == nil { return ctx.OK(result) } } return jsonapi.JSONErrorResponse(ctx, errors.Wrap(err, "Error listing users")) }) }
// List runs the list action. func (c *WorkItemCommentsController) List(ctx *app.ListWorkItemCommentsContext) error { offset, limit := computePagingLimts(ctx.PageOffset, ctx.PageLimit) return application.Transactional(c.db, func(appl application.Application) error { _, err := appl.WorkItems().Load(ctx, ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } res := &app.CommentList{} res.Data = []*app.Comment{} comments, tc, err := appl.Comments().List(ctx, ctx.ID, &offset, &limit) count := int(tc) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrInternal(err.Error())) } res.Meta = &app.CommentListMeta{TotalCount: count} res.Data = ConvertComments(ctx.RequestData, comments) res.Links = &app.PagingLinks{} setPagingLinks(res.Links, buildAbsoluteURL(ctx.RequestData), len(comments), offset, limit, count) return ctx.OK(res) }) }
// Create runs the create action. func (c *WorkItemCommentsController) Create(ctx *app.CreateWorkItemCommentsContext) error { return application.Transactional(c.db, func(appl application.Application) error { _, err := appl.WorkItems().Load(ctx, ctx.ID) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrNotFound(err.Error())) } currentUser, err := login.ContextIdentity(ctx) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } currentUserID, err := uuid.FromString(currentUser) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrUnauthorized(err.Error())) } reqComment := ctx.Payload.Data markup := rendering.NilSafeGetMarkup(reqComment.Attributes.Markup) newComment := comment.Comment{ ParentID: ctx.ID, Body: reqComment.Attributes.Body, Markup: markup, CreatedBy: currentUserID, } err = appl.Comments().Create(ctx, &newComment) if err != nil { return jsonapi.JSONErrorResponse(ctx, goa.ErrInternal(err.Error())) } res := &app.CommentSingle{ Data: ConvertComment(ctx.RequestData, &newComment), } return ctx.OK(res) }) }