// 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 }
// 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 }
// 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 }
// 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 }
// 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 }
// 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 }
// 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 }
// 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 }
// ParseWorkItemIDToUint64 does what it says func ParseWorkItemIDToUint64(wiIDStr string) (uint64, error) { wiID, err := strconv.ParseUint(wiIDStr, 10, 64) if err != nil { return 0, errors.NewNotFoundError("work item ID", wiIDStr) } return wiID, 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) }
func TestNewNotFoundError(t *testing.T) { t.Parallel() resource.Require(t, resource.UnitTest) param := "assigness" value := "10" err := errors.NewNotFoundError(param, value) assert.Equal(t, fmt.Sprintf("%s with id '%s' not found", param, value), err.Error()) }
// 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 }
// 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 }
// 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 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 }
// LoadFromDB returns the work item with the given ID in model representation. func (r *GormWorkItemRepository) LoadFromDB(ctx context.Context, ID string) (*WorkItem, error) { id, err := strconv.ParseUint(ID, 10, 64) if err != nil || id == 0 { // treating this as a not found error: the fact that we're using number internal is implementation detail return nil, errors.NewNotFoundError("work item", ID) } log.Info(nil, map[string]interface{}{ "pkg": "workitem", "wiID": ID, }, "Loading work item") res := WorkItem{} tx := r.db.First(&res, id) if tx.RecordNotFound() { log.Error(nil, map[string]interface{}{ "wiID": ID, }, "work item not found") return nil, errors.NewNotFoundError("work item", ID) } if tx.Error != nil { return nil, errors.NewInternalError(tx.Error.Error()) } return &res, 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 }
// 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 }
// LoadCategoryFromDB return work item link category for the name func (r *GormWorkItemLinkCategoryRepository) LoadCategoryFromDB(ctx context.Context, name string) (*WorkItemLinkCategory, error) { log.Info(ctx, map[string]interface{}{ "pkg": "link", "categoryName": name, }, "Loading work item link category: %s", name) res := WorkItemLinkCategory{} db := r.db.Model(&res).Where("name=?", name).First(&res) if db.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "wilcName": name, }, "work item link category not found") return nil, errors.NewNotFoundError("work item link category", name) } if db.Error != nil { return nil, errors.NewInternalError(db.Error.Error()) } return &res, 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 }
// Create implements application.WorkItemRepository func (r *UndoableWorkItemRepository) Create(ctx context.Context, typeID string, fields map[string]interface{}, creator string) (*app.WorkItem, error) { result, err := r.wrapped.Create(ctx, typeID, fields, creator) if err != nil { return result, errs.WithStack(err) } id, err := strconv.ParseUint(result.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 nil, errors.NewNotFoundError("work item", result.ID) } toDelete := WorkItem{ID: id} r.undo.Append(func(db *gorm.DB) error { db = db.Unscoped().Delete(&toDelete) return db.Error }) return result, errs.WithStack(err) }
// Load a single Iteration regardless of parent func (m *GormIterationRepository) Load(ctx context.Context, id uuid.UUID) (*Iteration, error) { defer goa.MeasureSince([]string{"goa", "db", "iteration", "get"}, time.Now()) var obj Iteration tx := m.db.Where("id = ?", id).First(&obj) if tx.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "iterationID": id.String(), }, "iteration cannot be found") return nil, errors.NewNotFoundError("Iteration", id.String()) } if tx.Error != nil { log.Error(ctx, map[string]interface{}{ "iterationID": id.String(), "err": tx.Error, }, "unable to load the iteration") return nil, errors.NewInternalError(tx.Error.Error()) } return &obj, nil }
// LoadTypeFromDB return work item link type for the given name in the correct link category // NOTE: Two link types can coexist with different categoryIDs. func (r *GormWorkItemLinkTypeRepository) LoadTypeFromDBByNameAndCategory(ctx context.Context, name string, categoryId satoriuuid.UUID) (*WorkItemLinkType, error) { log.Info(ctx, map[string]interface{}{ "pkg": "link", "wiltName": name, "categoryId": categoryId, }, "Loading work item link type %s with category ID %s", name, categoryId.String()) res := WorkItemLinkType{} db := r.db.Model(&res).Where("name=? AND link_category_id=?", name, categoryId.String()).First(&res) if db.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "wiltName": name, "categoryId": categoryId.String(), }, "work item link type not found") return nil, errors.NewNotFoundError("work item link type", name) } if db.Error != nil { return nil, errors.NewInternalError(db.Error.Error()) } return &res, 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 comment regardless of parent func (m *GormCommentRepository) Load(ctx context.Context, id uuid.UUID) (*Comment, error) { defer goa.MeasureSince([]string{"goa", "db", "comment", "get"}, time.Now()) var obj Comment tx := m.db.Where("id=?", id).First(&obj) if tx.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "commentID": id.String(), }, "comment search operation failed!") return nil, errors.NewNotFoundError("comment", id.String()) } if tx.Error != nil { log.Error(ctx, map[string]interface{}{ "commentID": id.String(), "err": tx.Error, }, "unable to load the comment") return nil, errors.NewInternalError(tx.Error.Error()) } return &obj, nil }
// Save updates the given work item in storage. Version must be the same as the one int the stored version // returns NotFoundError, VersionConflictError, ConversionError or InternalError func (r *GormWorkItemRepository) Save(ctx context.Context, wi app.WorkItem) (*app.WorkItem, error) { res := WorkItem{} id, err := strconv.ParseUint(wi.ID, 10, 64) if err != nil || id == 0 { return nil, errors.NewNotFoundError("work item", wi.ID) } log.Info(ctx, map[string]interface{}{ "pkg": "workitem", "wiID": wi.ID, }, "Looking for id for the work item repository") tx := r.db.First(&res, id) if tx.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "wiID": wi.ID, }, "work item repository not found") return nil, errors.NewNotFoundError("work item", wi.ID) } if tx.Error != nil { return nil, errors.NewInternalError(err.Error()) } if res.Version != wi.Version { return nil, errors.NewVersionConflictError("version conflict") } wiType, err := r.wir.LoadTypeFromDB(ctx, wi.Type) if err != nil { return nil, errors.NewBadParameterError("Type", wi.Type) } res.Version = res.Version + 1 res.Type = wi.Type res.Fields = Fields{} for fieldName, fieldDef := range wiType.Fields { if fieldName == SystemCreatedAt { continue } fieldValue := wi.Fields[fieldName] var err error res.Fields[fieldName], err = fieldDef.ConvertToModel(fieldName, fieldValue) if err != nil { return nil, errors.NewBadParameterError(fieldName, fieldValue) } } tx = tx.Where("Version = ?", wi.Version).Save(&res) if err := tx.Error; err != nil { log.Error(ctx, map[string]interface{}{ "wiID": wi.ID, "err": err, }, "unable to save the work item repository") return nil, errors.NewInternalError(err.Error()) } if tx.RowsAffected == 0 { return nil, errors.NewVersionConflictError("version conflict") } log.Info(ctx, map[string]interface{}{ "pkg": "workitem", "wiID": wi.ID, }, "Updated work item repository") return convertWorkItemModelToApp(wiType, &res) }
// ConvertLinkTypeToModel converts the incoming app representation of a work item link type to the model layout. // Values are only overwrriten if they are set in "in", otherwise the values in "out" remain. func ConvertLinkTypeToModel(in app.WorkItemLinkTypeSingle, out *WorkItemLinkType) error { attrs := in.Data.Attributes rel := in.Data.Relationships var err error if in.Data.ID != nil { id, err := satoriuuid.FromString(*in.Data.ID) if err != nil { //log.Printf("Error when converting %s to UUID: %s", *in.Data.ID, err.Error()) // treat as not found: clients don't know it must be a UUID return errors.NewNotFoundError("work item link type", id.String()) } out.ID = id } if in.Data.Type != EndpointWorkItemLinkTypes { return errors.NewBadParameterError("data.type", in.Data.Type).Expected(EndpointWorkItemLinkTypes) } if attrs != nil { // If the name is not nil, it MUST NOT be empty if attrs.Name != nil { if *attrs.Name == "" { return errors.NewBadParameterError("data.attributes.name", *attrs.Name) } out.Name = *attrs.Name } if attrs.Description != nil { out.Description = attrs.Description } if attrs.Version != nil { out.Version = *attrs.Version } // If the forwardName is not nil, it MUST NOT be empty if attrs.ForwardName != nil { if *attrs.ForwardName == "" { return errors.NewBadParameterError("data.attributes.forward_name", *attrs.ForwardName) } out.ForwardName = *attrs.ForwardName } // If the ReverseName is not nil, it MUST NOT be empty if attrs.ReverseName != nil { if *attrs.ReverseName == "" { return errors.NewBadParameterError("data.attributes.reverse_name", *attrs.ReverseName) } out.ReverseName = *attrs.ReverseName } if attrs.Topology != nil { if err := CheckValidTopology(*attrs.Topology); err != nil { return errs.WithStack(err) } out.Topology = *attrs.Topology } } if rel != nil && rel.LinkCategory != nil && rel.LinkCategory.Data != nil { d := rel.LinkCategory.Data // If the the link category is not nil, it MUST be "workitemlinkcategories" if d.Type != EndpointWorkItemLinkCategories { return errors.NewBadParameterError("data.relationships.link_category.data.type", d.Type).Expected(EndpointWorkItemLinkCategories) } // The the link category MUST NOT be empty if d.ID == "" { return errors.NewBadParameterError("data.relationships.link_category.data.id", d.ID) } out.LinkCategoryID, err = satoriuuid.FromString(d.ID) if err != nil { //log.Printf("Error when converting %s to UUID: %s", in.Data.ID, err.Error()) // treat as not found: clients don't know it must be a UUID return errors.NewNotFoundError("work item link category", d.ID) } } if rel != nil && rel.SourceType != nil && rel.SourceType.Data != nil { d := rel.SourceType.Data // If the the link type is not nil, it MUST be "workitemlinktypes" if d.Type != EndpointWorkItemTypes { return errors.NewBadParameterError("data.relationships.source_type.data.type", d.Type).Expected(EndpointWorkItemTypes) } // The the link type MUST NOT be empty if d.ID == "" { return errors.NewBadParameterError("data.relationships.source_type.data.id", d.ID) } out.SourceTypeName = d.ID } if rel != nil && rel.TargetType != nil && rel.TargetType.Data != nil { d := rel.TargetType.Data // If the the link type is not nil, it MUST be "workitemlinktypes" if d.Type != EndpointWorkItemTypes { return errors.NewBadParameterError("data.relationships.target_type.data.type", d.Type).Expected(EndpointWorkItemTypes) } // The the link type MUST NOT be empty if d.ID == "" { return errors.NewBadParameterError("data.relationships.target_type.data.id", d.ID) } out.TargetTypeName = d.ID } return nil }
// Save updates the given work item link category in storage. Version must be the same as the one int the stored version. // returns NotFoundError, VersionConflictError, ConversionError or InternalError func (r *GormWorkItemLinkCategoryRepository) Save(ctx context.Context, linkCat app.WorkItemLinkCategorySingle) (*app.WorkItemLinkCategorySingle, error) { res := WorkItemLinkCategory{} if linkCat.Data.ID == nil { return nil, errors.NewBadParameterError("data.id", linkCat.Data.ID) } id, err := satoriuuid.FromString(*linkCat.Data.ID) if err != nil { log.Error(ctx, map[string]interface{}{ "wilcID": *linkCat.Data.ID, "err": err, }, "error when converting %s to UUID: %s", *linkCat.Data.ID, err.Error()) // treat as not found: clients don't know it must be a UUID return nil, errors.NewNotFoundError("work item link category", id.String()) } if linkCat.Data.Type != EndpointWorkItemLinkCategories { return nil, errors.NewBadParameterError("data.type", linkCat.Data.Type).Expected(EndpointWorkItemLinkCategories) } // If the name is not nil, it MUST NOT be empty if linkCat.Data.Attributes.Name != nil && *linkCat.Data.Attributes.Name == "" { return nil, errors.NewBadParameterError("data.attributes.name", *linkCat.Data.Attributes.Name) } db := r.db.Model(&res).Where("id=?", *linkCat.Data.ID).First(&res) if db.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "wilcID": *linkCat.Data.ID, }, "work item link category not found") return nil, errors.NewNotFoundError("work item link category", id.String()) } if db.Error != nil { log.Error(ctx, map[string]interface{}{ "wilcID": *linkCat.Data.ID, "err": db.Error, }, "unable to find work item link category") return nil, errors.NewInternalError(db.Error.Error()) } if linkCat.Data.Attributes.Version == nil || res.Version != *linkCat.Data.Attributes.Version { return nil, errors.NewVersionConflictError("version conflict") } newLinkCat := WorkItemLinkCategory{ ID: id, Version: *linkCat.Data.Attributes.Version + 1, } if linkCat.Data.Attributes.Name != nil { newLinkCat.Name = *linkCat.Data.Attributes.Name } if linkCat.Data.Attributes.Description != nil { newLinkCat.Description = linkCat.Data.Attributes.Description } db = db.Save(&newLinkCat) if db.Error != nil { log.Error(ctx, map[string]interface{}{ "wilcID": newLinkCat.ID, "err": db.Error, }, "unable to save work item link category repository") return nil, errors.NewInternalError(db.Error.Error()) } log.Info(ctx, map[string]interface{}{ "pkg": "link", "wilcID": newLinkCat.ID, "newLinkCategory": newLinkCat, }, "Work item link category updated") result := ConvertLinkCategoryFromModel(newLinkCat) return &result, nil }
// ConvertLinkToModel converts the incoming app representation of a work item link to the model layout. // Values are only overwrriten if they are set in "in", otherwise the values in "out" remain. // NOTE: Only the LinkTypeID, SourceID, and TargetID fields will be set. // You need to preload the elements after calling this function. func ConvertLinkToModel(in app.WorkItemLinkSingle, out *WorkItemLink) error { attrs := in.Data.Attributes rel := in.Data.Relationships var err error if in.Data.ID != nil { id, err := satoriuuid.FromString(*in.Data.ID) if err != nil { //log.Printf("Error when converting %s to UUID: %s", *in.Data.ID, err.Error()) // treat as not found: clients don't know it must be a UUID return errors.NewNotFoundError("work item link", id.String()) } out.ID = id } if in.Data.Type != EndpointWorkItemLinks { return errors.NewBadParameterError("data.type", in.Data.Type).Expected(EndpointWorkItemLinks) } if attrs != nil { if attrs.Version != nil { out.Version = *attrs.Version } } if rel != nil && rel.LinkType != nil && rel.LinkType.Data != nil { d := rel.LinkType.Data // If the the link category is not nil, it MUST be "workitemlinktypes" if d.Type != EndpointWorkItemLinkTypes { return errors.NewBadParameterError("data.relationships.link_type.data.type", d.Type).Expected(EndpointWorkItemLinkTypes) } // The the link type id MUST NOT be empty if d.ID == "" { return errors.NewBadParameterError("data.relationships.link_type.data.id", d.ID) } if out.LinkTypeID, err = satoriuuid.FromString(d.ID); err != nil { //log.Printf("Error when converting %s to UUID: %s", in.Data.ID, err.Error()) // treat as not found: clients don't know it must be a UUID return errors.NewNotFoundError("work item link type", d.ID) } } if rel != nil && rel.Source != nil && rel.Source.Data != nil { d := rel.Source.Data // If the the source type is not nil, it MUST be "workitems" if d.Type != EndpointWorkItems { return errors.NewBadParameterError("data.relationships.source.data.type", d.Type).Expected(EndpointWorkItems) } // The the work item id MUST NOT be empty if d.ID == "" { return errors.NewBadParameterError("data.relationships.source.data.id", d.ID) } if out.SourceID, err = strconv.ParseUint(d.ID, 10, 64); err != nil { return errors.NewBadParameterError("data.relationships.source.data.id", d.ID) } } if rel != nil && rel.Target != nil && rel.Target.Data != nil { d := rel.Target.Data // If the the target type is not nil, it MUST be "workitems" if d.Type != EndpointWorkItems { return errors.NewBadParameterError("data.relationships.target.data.type", d.Type).Expected(EndpointWorkItems) } // The the work item id MUST NOT be empty if d.ID == "" { return errors.NewBadParameterError("data.relationships.target.data.id", d.ID) } if out.TargetID, err = strconv.ParseUint(d.ID, 10, 64); err != nil { return errors.NewBadParameterError("data.relationships.target.data.id", d.ID) } } return nil }