// Save updates the given space in the db. Version must be the same as the one in the stored version // returns NotFoundError, BadParameterError, VersionConflictError or InternalError func (r *GormRepository) Save(ctx context.Context, p *Space) (*Space, error) { pr := Space{} tx := r.db.Where("id=?", p.ID).First(&pr) oldVersion := p.Version p.Version++ if tx.RecordNotFound() { // treating this as a not found error: the fact that we're using number internal is implementation detail return nil, errors.NewNotFoundError("space", p.ID.String()) } if err := tx.Error; err != nil { return nil, errors.NewInternalError(err.Error()) } tx = tx.Where("Version = ?", oldVersion).Save(p) if err := tx.Error; err != nil { if gormsupport.IsCheckViolation(tx.Error, "spaces_name_check") { return nil, errors.NewBadParameterError("Name", p.Name).Expected("not empty") } if gormsupport.IsUniqueViolation(tx.Error, "spaces_name_idx") { return nil, errors.NewBadParameterError("Name", p.Name).Expected("unique") } return nil, errors.NewInternalError(err.Error()) } if tx.RowsAffected == 0 { return nil, errors.NewVersionConflictError("version conflict") } log.Info(ctx, map[string]interface{}{ "pkg": "space", "spaceID": p.ID, }, "space updated successfully") return p, nil }
// Create creates a new work item link type in the repository. // Returns BadParameterError, ConversionError or InternalError func (r *GormWorkItemLinkTypeRepository) Create(ctx context.Context, name string, description *string, sourceTypeName, targetTypeName, forwardName, reverseName, topology string, linkCategoryID satoriuuid.UUID) (*app.WorkItemLinkTypeSingle, error) { linkType := &WorkItemLinkType{ Name: name, Description: description, SourceTypeName: sourceTypeName, TargetTypeName: targetTypeName, ForwardName: forwardName, ReverseName: reverseName, Topology: topology, LinkCategoryID: linkCategoryID, } if err := linkType.CheckValidForCreation(); err != nil { return nil, errs.WithStack(err) } // Check link category exists linkCategory := WorkItemLinkCategory{} db := r.db.Where("id=?", linkType.LinkCategoryID).Find(&linkCategory) if db.RecordNotFound() { return nil, errors.NewBadParameterError("work item link category", linkType.LinkCategoryID) } if db.Error != nil { return nil, errors.NewInternalError(fmt.Sprintf("Failed to find work item link category: %s", db.Error.Error())) } db = r.db.Create(linkType) if db.Error != nil { return nil, errors.NewInternalError(db.Error.Error()) } // Convert the created link type entry into a JSONAPI response result := ConvertLinkTypeFromModel(*linkType) return &result, nil }
// 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}) }
// Save updates the given iteration in the db. Version must be the same as the one in the stored version // returns NotFoundError, VersionConflictError or InternalError func (m *GormIterationRepository) Save(ctx context.Context, i Iteration) (*Iteration, error) { itr := Iteration{} tx := m.db.Where("id=?", i.ID).First(&itr) if tx.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "iterationID": i.ID, }, "iteration cannot be found") // treating this as a not found error: the fact that we're using number internal is implementation detail return nil, errors.NewNotFoundError("iteration", i.ID.String()) } if err := tx.Error; err != nil { log.Error(ctx, map[string]interface{}{ "iterationID": i.ID, "err": err, }, "unknown error happened when searching the iteration") return nil, errors.NewInternalError(err.Error()) } tx = tx.Save(&i) if err := tx.Error; err != nil { log.Error(ctx, map[string]interface{}{ "iterationID": i.ID, "err": err, }, "unable to save the iterations") return nil, errors.NewInternalError(err.Error()) } return &i, nil }
// Create creates a new work item in the repository // returns BadParameterError, ConversionError or InternalError func (r *GormWorkItemTypeRepository) Create(ctx context.Context, extendedTypeName *string, name string, fields map[string]app.FieldDefinition) (*app.WorkItemType, error) { existing, _ := r.LoadTypeFromDB(ctx, name) if existing != nil { log.Error(ctx, map[string]interface{}{"witName": name}, "unable to create new work item type") return nil, errors.NewBadParameterError("name", name) } allFields := map[string]FieldDefinition{} path := name if extendedTypeName != nil { extendedType := WorkItemType{} db := r.db.First(&extendedType, "name = ?", extendedTypeName) if db.RecordNotFound() { return nil, errors.NewBadParameterError("extendedTypeName", *extendedTypeName) } if err := db.Error; err != nil { return nil, errors.NewInternalError(err.Error()) } // copy fields from extended type for key, value := range extendedType.Fields { allFields[key] = value } path = extendedType.Path + pathSep + name } // now process new fields, checking whether they are ok to add. for field, definition := range fields { existing, exists := allFields[field] ct, err := convertFieldTypeToModels(*definition.Type) if err != nil { return nil, errs.WithStack(err) } converted := FieldDefinition{ Required: definition.Required, Type: ct, } if exists && !compatibleFields(existing, converted) { return nil, fmt.Errorf("incompatible change for field %s", field) } allFields[field] = converted } created := WorkItemType{ Version: 0, Name: name, Path: path, Fields: allFields, } if err := r.db.Save(&created).Error; err != nil { return nil, errors.NewInternalError(err.Error()) } result := convertTypeFromModels(&created) return &result, nil }
// Delete deletes the space with the given id // returns NotFoundError or InternalError func (r *GormRepository) Delete(ctx context.Context, ID satoriuuid.UUID) error { if ID == satoriuuid.Nil { log.Error(ctx, map[string]interface{}{ "spaceID": ID.String(), }, "unable to find the space by ID") return errors.NewNotFoundError("space", ID.String()) } space := Space{ID: ID} tx := r.db.Delete(space) if err := tx.Error; err != nil { log.Error(ctx, map[string]interface{}{ "spaceID": ID.String(), }, "unable to delete the space") return errors.NewInternalError(err.Error()) } if tx.RowsAffected == 0 { log.Error(ctx, map[string]interface{}{ "spaceID": ID.String(), }, "none row was affected by the deletion operation") return errors.NewNotFoundError("space", ID.String()) } return nil }
// SearchFullText Search returns work items for the given query func (r *GormSearchRepository) SearchFullText(ctx context.Context, rawSearchString string, start *int, limit *int) ([]*app.WorkItem, uint64, error) { // parse // generateSearchQuery // .... parsedSearchDict, err := parseSearchString(rawSearchString) if err != nil { return nil, 0, errs.WithStack(err) } sqlSearchQueryParameter := generateSQLSearchInfo(parsedSearchDict) var rows []workitem.WorkItem rows, count, err := r.search(ctx, sqlSearchQueryParameter, parsedSearchDict.workItemTypes, start, limit) if err != nil { return nil, 0, errs.WithStack(err) } result := make([]*app.WorkItem, len(rows)) for index, value := range rows { var err error // FIXME: Against best practice http://go-database-sql.org/retrieving.html wiType, err := r.wir.LoadTypeFromDB(ctx, value.Type) if err != nil { return nil, 0, errors.NewInternalError(err.Error()) } result[index], err = convertFromModel(*wiType, value) if err != nil { return nil, 0, errors.NewConversionError(err.Error()) } } return result, count, nil }
// Delete implements application.WorkItemRepository func (r *UndoableWorkItemRepository) Delete(ctx context.Context, ID string) error { id, err := strconv.ParseUint(ID, 10, 64) if err != nil { // treating this as a not found error: the fact that we're using number internal is implementation detail return errors.NewNotFoundError("work item", ID) } log.Info(ctx, map[string]interface{}{ "pkg": "workitem", "id": id, }, "Loading work iteme") old := WorkItem{} db := r.wrapped.db.First(&old, id) if db.Error != nil { return errors.NewInternalError(fmt.Sprintf("could not load %s, %s", ID, db.Error.Error())) } err = r.wrapped.Delete(ctx, ID) if err == nil { r.undo.Append(func(db *gorm.DB) error { old.DeletedAt = nil db = db.Save(&old) return db.Error }) } return errs.WithStack(err) }
// Delete deletes the work item link category with the given id // returns NotFoundError or InternalError func (r *GormWorkItemLinkCategoryRepository) Delete(ctx context.Context, ID string) error { id, err := satoriuuid.FromString(ID) if err != nil { // treat as not found: clients don't know it must be a UUID return errors.NewNotFoundError("work item link category", ID) } var cat = WorkItemLinkCategory{ ID: id, } log.Info(ctx, map[string]interface{}{ "pkg": "link", "wilcID": ID, }, "Work item link category to delete") db := r.db.Delete(&cat) if db.Error != nil { return errors.NewInternalError(db.Error.Error()) } if db.RowsAffected == 0 { return errors.NewNotFoundError("work item link category", id.String()) } return nil }
// Load returns the work item link type for the given ID. // Returns NotFoundError, ConversionError or InternalError func (r *GormWorkItemLinkTypeRepository) Load(ctx context.Context, ID string) (*app.WorkItemLinkTypeSingle, error) { id, err := satoriuuid.FromString(ID) if err != nil { // treat as not found: clients don't know it must be a UUID return nil, errors.NewNotFoundError("work item link type", ID) } log.Info(ctx, map[string]interface{}{ "pkg": "link", "wiltID": ID, }, "Loading work item link type") res := WorkItemLinkType{} db := r.db.Model(&res).Where("id=?", ID).First(&res) if db.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "wiltID": ID, }, "work item link type not found") return nil, errors.NewNotFoundError("work item link type", id.String()) } if db.Error != nil { return nil, errors.NewInternalError(db.Error.Error()) } // Convert the created link type entry into a JSONAPI response result := ConvertLinkTypeFromModel(res) return &result, nil }
// Create creates a new work item in the repository // returns BadParameterError, ConversionError or InternalError func (r *GormWorkItemRepository) Create(ctx context.Context, typeID string, fields map[string]interface{}, creator string) (*app.WorkItem, error) { wiType, err := r.wir.LoadTypeFromDB(ctx, typeID) if err != nil { return nil, errors.NewBadParameterError("type", typeID) } wi := WorkItem{ Type: typeID, Fields: Fields{}, } fields[SystemCreator] = creator for fieldName, fieldDef := range wiType.Fields { if fieldName == SystemCreatedAt { continue } fieldValue := fields[fieldName] var err error wi.Fields[fieldName], err = fieldDef.ConvertToModel(fieldName, fieldValue) if err != nil { return nil, errors.NewBadParameterError(fieldName, fieldValue) } if fieldName == SystemDescription && wi.Fields[fieldName] != nil { description := rendering.NewMarkupContentFromMap(wi.Fields[fieldName].(map[string]interface{})) if !rendering.IsMarkupSupported(description.Markup) { return nil, errors.NewBadParameterError(fieldName, fieldValue) } } } tx := r.db if err = tx.Create(&wi).Error; err != nil { return nil, errors.NewInternalError(err.Error()) } return convertWorkItemModelToApp(wiType, &wi) }
// LoadTypeFromDB return work item type for the given id func (r *GormWorkItemTypeRepository) LoadTypeFromDB(ctx context.Context, name string) (*WorkItemType, error) { log.Logger().Infoln("Loading work item type", name) res, ok := cache.Get(name) if !ok { log.Info(ctx, map[string]interface{}{ "pkg": "workitem", "type": name, }, "Work item type doesn't exist in the cache. Loading from DB...") res = WorkItemType{} db := r.db.Model(&res).Where("name=?", name).First(&res) if db.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "witName": name, }, "work item type repository not found") return nil, errors.NewNotFoundError("work item type", name) } if err := db.Error; err != nil { return nil, errors.NewInternalError(err.Error()) } cache.Put(res) } return &res, nil }
// Delete deletes the work item link with the given id // returns NotFoundError or InternalError func (r *GormWorkItemLinkRepository) Delete(ctx context.Context, ID string) error { id, err := satoriuuid.FromString(ID) if err != nil { // treat as not found: clients don't know it must be a UUID return errors.NewNotFoundError("work item link", ID) } var link = WorkItemLink{ ID: id, } log.Info(ctx, map[string]interface{}{ "pkg": "link", "wilID": ID, }, "Deleting the work item link repository") db := r.db.Delete(&link) if db.Error != nil { log.Error(ctx, map[string]interface{}{ "wilID": ID, "err": db.Error, }, "unable to delete work item link repository") return errors.NewInternalError(db.Error.Error()) } if db.RowsAffected == 0 { return errors.NewNotFoundError("work item link", id.String()) } return nil }
func TestNewInternalError(t *testing.T) { t.Parallel() resource.Require(t, resource.UnitTest) err := errors.NewInternalError("System disk could not be read") // not sure what assertion to do here. t.Log(err) }
// Save updates the given work item link in storage. Version must be the same as the one int the stored version. // returns NotFoundError, VersionConflictError, ConversionError or InternalError func (r *GormWorkItemLinkRepository) Save(ctx context.Context, lt app.WorkItemLinkSingle) (*app.WorkItemLinkSingle, error) { res := WorkItemLink{} if lt.Data.ID == nil { return nil, errors.NewBadParameterError("work item link", nil) } db := r.db.Model(&res).Where("id=?", *lt.Data.ID).First(&res) if db.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "wilID": *lt.Data.ID, }, "work item link not found") return nil, errors.NewNotFoundError("work item link", *lt.Data.ID) } if db.Error != nil { log.Error(ctx, map[string]interface{}{ "wilID": *lt.Data.ID, "err": db.Error, }, "unable to find work item link") return nil, errors.NewInternalError(db.Error.Error()) } if lt.Data.Attributes.Version == nil || res.Version != *lt.Data.Attributes.Version { return nil, errors.NewVersionConflictError("version conflict") } if err := ConvertLinkToModel(lt, &res); err != nil { return nil, errs.WithStack(err) } res.Version = res.Version + 1 if err := r.ValidateCorrectSourceAndTargetType(ctx, res.SourceID, res.TargetID, res.LinkTypeID); err != nil { return nil, errs.WithStack(err) } db = r.db.Save(&res) if db.Error != nil { log.Error(ctx, map[string]interface{}{ "wilID": res.ID, "err": db.Error, }, "unable to save work item link") return nil, errors.NewInternalError(db.Error.Error()) } log.Info(ctx, map[string]interface{}{ "pkg": "link", "wilID": res.ID, }, "Work item link updated") result := ConvertLinkFromModel(res) return &result, nil }
// Load returns the work item for the given id // returns NotFoundError, ConversionError or InternalError func (r *GormWorkItemRepository) Load(ctx context.Context, ID string) (*app.WorkItem, error) { res, err := r.LoadFromDB(ctx, ID) if err != nil { return nil, errs.WithStack(err) } wiType, err := r.wir.LoadTypeFromDB(ctx, res.Type) if err != nil { return nil, errors.NewInternalError(err.Error()) } return convertWorkItemModelToApp(wiType, res) }
// DeleteRelatedLinks deletes all links in which the source or target equals the // given work item ID. func (r *GormWorkItemLinkRepository) DeleteRelatedLinks(ctx context.Context, wiIDStr string) error { wiId, err := strconv.ParseUint(wiIDStr, 10, 64) if err != nil { // treat as not found: clients don't know it must be a uint64 return errors.NewNotFoundError("work item link", wiIDStr) } db := r.db.Where("? in (source_id, target_id)", wiId).Delete(&WorkItemLink{}) if db.Error != nil { return errors.NewInternalError(db.Error.Error()) } return nil }
// Delete a single comment func (m *GormCommentRepository) Delete(ctx context.Context, id uuid.UUID) error { if id == uuid.Nil { return errors.NewNotFoundError("comment", id.String()) } tx := m.db.Delete(&Comment{ID: id}) if tx.RowsAffected == 0 { return errors.NewNotFoundError("comment", id.String()) } if err := tx.Error; err != nil { return errors.NewInternalError(err.Error()) } return nil }
// Save a single comment func (m *GormCommentRepository) Save(ctx context.Context, comment *Comment) (*Comment, error) { c := Comment{} tx := m.db.Where("id=?", comment.ID).First(&c) if tx.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "commentID": comment.ID, }, "comment not found!") // treating this as a not found error: the fact that we're using number internal is implementation detail return nil, errors.NewNotFoundError("comment", comment.ID.String()) } if err := tx.Error; err != nil { log.Error(ctx, map[string]interface{}{ "commentID": comment.ID, "err": err, }, "comment search operation failed!") return nil, errors.NewInternalError(err.Error()) } // make sure no comment is created with an empty 'markup' value if comment.Markup == "" { comment.Markup = rendering.SystemMarkupDefault } tx = tx.Save(comment) if err := tx.Error; err != nil { log.Error(ctx, map[string]interface{}{ "commentID": comment.ID, "err": err, }, "unable to save the comment!") return nil, errors.NewInternalError(err.Error()) } log.Debug(ctx, map[string]interface{}{ "pkg": "comment", "commentID": comment.ID, }, "Comment updated!") return comment, nil }
// Load a single Area regardless of parent func (m *GormAreaRepository) Load(ctx context.Context, id uuid.UUID) (*Area, error) { defer goa.MeasureSince([]string{"goa", "db", "Area", "get"}, time.Now()) var obj Area tx := m.db.Where("id = ?", id).First(&obj) if tx.RecordNotFound() { return nil, errors.NewNotFoundError("Area", id.String()) } if tx.Error != nil { return nil, errors.NewInternalError(tx.Error.Error()) } return &obj, nil }
// Load multiple areas func (m *GormAreaRepository) LoadMultiple(ctx context.Context, ids []uuid.UUID) ([]*Area, error) { defer goa.MeasureSince([]string{"goa", "db", "Area", "getmultiple"}, time.Now()) var objs []*Area for i := 0; i < len(ids); i++ { m.db = m.db.Or("id = ?", ids[i]) } tx := m.db.Find(&objs) if tx.Error != nil { return nil, errors.NewInternalError(tx.Error.Error()) } return objs, nil }
// ErrorHandler turns a Go error into an JSONAPI HTTP response. It should be placed in the middleware chain // below the logger middleware so the logger properly logs the HTTP response. ErrorHandler // understands instances of goa.ServiceError and returns the status and response body embodied in // them, it turns other Go error types into a 500 internal error response. // If verbose is false the details of internal errors is not included in HTTP responses. // If you use github.com/pkg/errors then wrapping the error will allow a trace to be printed to the logs func ErrorHandler(service *goa.Service, verbose bool) goa.Middleware { return func(h goa.Handler) goa.Handler { return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { e := h(ctx, rw, req) if e == nil { return nil } cause := errs.Cause(e) status := http.StatusInternalServerError var respBody interface{} respBody, status = ErrorToJSONAPIErrors(e) rw.Header().Set("Content-Type", ErrorMediaIdentifier) if err, ok := cause.(goa.ServiceError); ok { status = err.ResponseStatus() //respBody = err goa.ContextResponse(ctx).ErrorCode = err.Token() //rw.Header().Set("Content-Type", ErrorMediaIdentifier) } else { //respBody = e.Error() //rw.Header().Set("Content-Type", "text/plain") } if status >= 500 && status < 600 { //reqID := ctx.Value(reqIDKey) reqID := ctx.Value(1) // TODO remove this hack if reqID == nil { reqID = shortID() //ctx = context.WithValue(ctx, reqIDKey, reqID) ctx = context.WithValue(ctx, 1, reqID) // TODO remove this hack } log.Error(ctx, map[string]interface{}{ "msg": respBody, "err": fmt.Sprintf("%+v", e), }, "uncaught error detected in ErrorHandler") if !verbose { rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier) msg := errors.NewInternalError(fmt.Sprintf("%s [%s]", http.StatusText(http.StatusInternalServerError), reqID)) //respBody = goa.ErrInternal(msg) respBody, status = ErrorToJSONAPIErrors(msg) // Preserve the ID of the original error as that's what gets logged, the client // received error ID must match the original // TODO for JSONAPI this won't work I guess. if origErrID := goa.ContextResponse(ctx).ErrorCode; origErrID != "" { respBody.(*goa.ErrorResponse).ID = origErrID } } } return service.Send(ctx, status, respBody) } } }
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 }
// Load returns the space for the given id // returns NotFoundError or InternalError func (r *GormRepository) Load(ctx context.Context, ID satoriuuid.UUID) (*Space, error) { res := Space{} tx := r.db.Where("id=?", ID).First(&res) if tx.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "spaceID": ID.String(), }, "state or known referer was empty") return nil, errors.NewNotFoundError("space", ID.String()) } if tx.Error != nil { return nil, errors.NewInternalError(tx.Error.Error()) } return &res, nil }
func (r *GormWorkItemRepository) GetCountsPerIteration(ctx context.Context, spaceID uuid.UUID) (map[string]WICountsPerIteration, error) { var res []WICountsPerIteration db := r.db.Table("work_items").Select(`iterations.id as IterationId, count(*) as Total, count( case fields->>'system.state' when 'closed' then '1' else null end ) as Closed`).Joins(`left join iterations on fields@> concat('{"system.iteration": "', iterations.id, '"}')::jsonb`).Where(`iterations.space_id = ? and work_items.deleted_at IS NULL`, spaceID).Group(`IterationId`).Scan(&res) if db.Error != nil { return nil, errors.NewInternalError(db.Error.Error()) } countsMap := map[string]WICountsPerIteration{} for _, iterationWithCount := range res { countsMap[iterationWithCount.IterationId] = iterationWithCount } return countsMap, nil }
// Create creates a new work item link category in the repository. // Returns BadParameterError, ConversionError or InternalError func (r *GormWorkItemLinkCategoryRepository) Create(ctx context.Context, name *string, description *string) (*app.WorkItemLinkCategorySingle, error) { if name == nil || *name == "" { return nil, errors.NewBadParameterError("name", name) } created := WorkItemLinkCategory{ // Omit "lifecycle" and "ID" fields as they will be filled by the DB Name: *name, Description: description, } db := r.db.Create(&created) if db.Error != nil { return nil, errors.NewInternalError(db.Error.Error()) } // Convert the created link category entry into a JSONAPI response result := ConvertLinkCategoryFromModel(created) return &result, nil }
// ListChildren fetches all Areas belonging to a parent - list all child areas. func (m *GormAreaRepository) ListChildren(ctx context.Context, parentArea *Area) ([]*Area, error) { defer goa.MeasureSince([]string{"goa", "db", "Area", "querychild"}, time.Now()) var objs []*Area predicateString := (parentArea.ID).String() if parentArea.Path != "" { predicateString = parentArea.Path + "." + predicateString } tx := m.db.Where("path ~ ?", ConvertToLtreeFormat(predicateString)).Find(&objs) if tx.RecordNotFound() { return nil, errors.NewNotFoundError("Area", parentArea.ID.String()) } if tx.Error != nil { return nil, errors.NewInternalError(tx.Error.Error()) } return objs, nil }
// List returns work item selected by the given criteria.Expression, starting with start (zero-based) and returning at most limit items func (r *GormWorkItemRepository) List(ctx context.Context, criteria criteria.Expression, start *int, limit *int) ([]*app.WorkItem, uint64, error) { result, count, err := r.listItemsFromDB(ctx, criteria, start, limit) if err != nil { return nil, 0, errs.WithStack(err) } res := make([]*app.WorkItem, len(result)) for index, value := range result { wiType, err := r.wir.LoadTypeFromDB(ctx, value.Type) if err != nil { return nil, 0, errors.NewInternalError(err.Error()) } res[index], err = convertWorkItemModelToApp(wiType, &value) } return res, count, nil }
// Delete deletes the work item with the given id // returns NotFoundError or InternalError func (r *GormWorkItemRepository) Delete(ctx context.Context, ID string) error { var workItem = WorkItem{} id, err := strconv.ParseUint(ID, 10, 64) if err != nil || id == 0 { // treat as not found: clients don't know it must be a number return errors.NewNotFoundError("work item", ID) } workItem.ID = id tx := r.db.Delete(workItem) if err = tx.Error; err != nil { return errors.NewInternalError(err.Error()) } if tx.RowsAffected == 0 { return errors.NewNotFoundError("work item", ID) } return nil }
// LoadTypeFromDB return work item link type for the given ID func (r *GormWorkItemLinkTypeRepository) LoadTypeFromDBByID(ctx context.Context, ID satoriuuid.UUID) (*WorkItemLinkType, error) { log.Info(ctx, map[string]interface{}{ "pkg": "link", "wiltID": ID.String(), }, "Loading work item link type with ID ", ID) res := WorkItemLinkType{} db := r.db.Model(&res).Where("ID=?", ID.String()).First(&res) if db.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "wiltID": ID.String(), }, "work item link type not found") return nil, errors.NewNotFoundError("work item link type", ID.String()) } if db.Error != nil { return nil, errors.NewInternalError(db.Error.Error()) } return &res, nil }