// Transactional executes the given function in a transaction. If todo returns an error, the transaction is rolled back func Transactional(db DB, todo func(f Application) error) error { var tx Transaction var err error if tx, err = db.BeginTransaction(); err != nil { log.Error(nil, map[string]interface{}{ "err": err, }, "database BeginTransaction failed!") return errors.WithStack(err) } if err := todo(tx); err != nil { log.Debug(nil, map[string]interface{}{ "pkg": "application", }, "Rolling back the transaction...") tx.Rollback() log.Error(nil, map[string]interface{}{ "err": err, }, "database transaction failed!") return errors.WithStack(err) } log.Debug(nil, map[string]interface{}{ "pkg": "application", }, "Commit the transaction!") return tx.Commit() }
// 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 }
// 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 }
// Migrate executes the required migration of the database on startup. // For each successful migration, an entry will be written into the "version" // table, that states when a certain version was reached. func Migrate(db *sql.DB) error { var err error if db == nil { return errs.Errorf("Database handle is nil\n") } m := getMigrations() var tx *sql.Tx for nextVersion := int64(0); nextVersion < int64(len(m)) && err == nil; nextVersion++ { tx, err = db.Begin() if err != nil { return errs.Errorf("Failed to start transaction: %s\n", err) } err = migrateToNextVersion(tx, &nextVersion, m) if err != nil { oldErr := err log.Info(nil, map[string]interface{}{ "pkg": "migration", "nextVersion": nextVersion, "migrations": m, "err": err, }, "Rolling back transaction due to: ", err) if err = tx.Rollback(); err != nil { log.Error(nil, map[string]interface{}{ "nextVersion": nextVersion, "migrations": m, "err": err, }, "error while rolling back transaction: ", err) return errs.Errorf("Error while rolling back transaction: %s\n", err) } return oldErr } if err = tx.Commit(); err != nil { log.Error(nil, map[string]interface{}{ "migrations": m, "err": err, }, "error during transaction commit: ", err) return errs.Errorf("Error during transaction commit: %s\n", err) } } if err != nil { log.Error(nil, map[string]interface{}{ "migrations": m, "err": err, }, "migration failed with error: ", err) return errs.Errorf("Migration failed with error: %s\n", err) } return nil }
// Save updates the given tracker in storage. // returns NotFoundError, ConversionError or InternalError func (r *GormTrackerRepository) Save(ctx context.Context, t app.Tracker) (*app.Tracker, error) { res := Tracker{} id, err := strconv.ParseUint(t.ID, 10, 64) if err != nil || id == 0 { return nil, NotFoundError{entity: "tracker", ID: t.ID} } log.Info(ctx, map[string]interface{}{ "pkg": "remoteworkitem", "trackerID": id, }, "Looking for a tracker repository with id ", id) tx := r.db.First(&res, id) if tx.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "trackerID": id, }, "tracker repository not found") return nil, NotFoundError{entity: "tracker", ID: t.ID} } _, present := RemoteWorkItemImplRegistry[t.Type] // Ensure we support this remote tracker. if present != true { return nil, BadParameterError{parameter: "type", value: t.Type} } newT := Tracker{ ID: id, URL: t.URL, Type: t.Type} if err := tx.Save(&newT).Error; err != nil { log.Error(ctx, map[string]interface{}{ "trackerID": newT.ID, "err": err, }, "unable to save tracker repository") return nil, InternalError{simpleError{err.Error()}} } log.Info(ctx, map[string]interface{}{ "pkg": "remoteworkitem", "tracker": newT.ID, }, "Tracker repository successfully updated") t2 := app.Tracker{ ID: strconv.FormatUint(id, 10), URL: t.URL, Type: t.Type} return &t2, 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 }
// 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 }
// 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)) }) }
// Load returns the tracker configuration for the given id // returns NotFoundError, ConversionError or InternalError func (r *GormTrackerRepository) Load(ctx context.Context, ID string) (*app.Tracker, 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, NotFoundError{"tracker", ID} } log.Info(ctx, map[string]interface{}{ "pkg": "remoteworkitem", "trackerID": id, }, "Loading tracker repository...") res := Tracker{} tx := r.db.First(&res, id) if tx.RecordNotFound() { log.Error(ctx, map[string]interface{}{ "trackerID": ID, }, "tracker repository not found") return nil, NotFoundError{"tracker", ID} } if tx.Error != nil { return nil, InternalError{simpleError{fmt.Sprintf("error while loading: %s", tx.Error.Error())}} } t := app.Tracker{ ID: strconv.FormatUint(res.ID, 10), URL: res.URL, Type: res.Type} return &t, nil }
// Load returns the tracker query for the given id // returns NotFoundError, ConversionError or InternalError func (r *GormTrackerQueryRepository) Load(ctx context.Context, ID string) (*app.TrackerQuery, 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, NotFoundError{"tracker query", ID} } log.Info(ctx, map[string]interface{}{ "pkg": "remoteworkitem", "trackerQueryid": id, }, "Loading the tracker query") res := TrackerQuery{} if r.db.First(&res, id).RecordNotFound() { log.Error(ctx, map[string]interface{}{ "trackerID": id, }, "tracker resource not found") return nil, NotFoundError{"tracker query", ID} } tq := app.TrackerQuery{ ID: strconv.FormatUint(res.ID, 10), Query: res.Query, Schedule: res.Schedule, TrackerID: strconv.FormatUint(res.TrackerID, 10)} return &tq, 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 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 }
func fetchTrackerQueries(db *gorm.DB) []trackerSchedule { tsList := []trackerSchedule{} err := db.Table("tracker_queries").Select("trackers.id as tracker_id, trackers.url, trackers.type as tracker_type, tracker_queries.query, tracker_queries.schedule").Joins("left join trackers on tracker_queries.tracker_id = trackers.id").Where("trackers.deleted_at is NULL AND tracker_queries.deleted_at is NULL").Scan(&tsList).Error if err != nil { log.Error(nil, map[string]interface{}{ "err": err, }, "fetch operation failed for tracker queries") } return tsList }
// 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) }
// 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 }
// 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 }
// CanStartIteration checks the rule - Only one iteration from a space can have state=start at a time. // More rules can be added as needed in this function func (m *GormIterationRepository) CanStartIteration(ctx context.Context, i *Iteration) (bool, error) { var count int64 m.db.Model(&Iteration{}).Where("space_id=? and state=?", i.SpaceID, IterationStateStart).Count(&count) if count != 0 { log.Error(ctx, map[string]interface{}{ "iterationID": i.ID, "spaceID": i.SpaceID, }, "one iteration from given space is already running!") return false, errors.NewBadParameterError("state", "One iteration from given space is already running") } return true, 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 }
// ContextIdentity returns the identity's ID found in given context // Uses tokenManager.Locate to fetch the identity of currently logged in user func ContextIdentity(ctx context.Context) (string, error) { tm := ReadTokenManagerFromContext(ctx) if tm == nil { log.Error(ctx, map[string]interface{}{ "token": tm, }, "missing token manager") return "", errs.New("Missing token manager") } uuid, err := tm.Locate(ctx) if err != nil { // TODO : need a way to define user as Guest log.Error(ctx, map[string]interface{}{ "uuid": uuid, "tm": tm, "err": err, }, "identity belongs to a Guest User") return "", errs.WithStack(err) } return uuid.String(), 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) } } }
// List all Iterations related to a single item func (m *GormIterationRepository) List(ctx context.Context, spaceID uuid.UUID) ([]*Iteration, error) { defer goa.MeasureSince([]string{"goa", "db", "iteration", "query"}, time.Now()) var objs []*Iteration err := m.db.Where("space_id = ?", spaceID).Find(&objs).Error if err != nil && err != gorm.ErrRecordNotFound { log.Error(ctx, map[string]interface{}{ "spaceID": spaceID, "err": err, }, "unable to list the iterations") return nil, errs.WithStack(err) } return objs, 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 }
// Create creates a new record. func (m *GormIterationRepository) Create(ctx context.Context, u *Iteration) error { defer goa.MeasureSince([]string{"goa", "db", "iteration", "create"}, time.Now()) u.ID = uuid.NewV4() u.State = IterationStateNew err := m.db.Create(u).Error if err != nil { log.Error(ctx, map[string]interface{}{ "iterationID": u.ID, "err": err, }, "unable to create the iteration") return errs.WithStack(err) } return nil }
// Show runs the show action. func (c *SearchController) Show(ctx *app.ShowSearchContext) error { var offset int var limit int offset, limit = computePagingLimts(ctx.PageOffset, ctx.PageLimit) // ToDo : Keep URL registeration central somehow. hostString := ctx.RequestData.Host if hostString == "" { hostString = configuration.GetHTTPAddress() } urlRegexString := fmt.Sprintf("(?P<domain>%s)(?P<path>/work-item/list/detail/)(?P<id>\\d*)", hostString) search.RegisterAsKnownURL(search.HostRegistrationKeyForListWI, urlRegexString) urlRegexString = fmt.Sprintf("(?P<domain>%s)(?P<path>/work-item/board/detail/)(?P<id>\\d*)", hostString) search.RegisterAsKnownURL(search.HostRegistrationKeyForBoardWI, urlRegexString) return application.Transactional(c.db, func(appl application.Application) error { //return transaction.Do(c.ts, func() error { result, c, err := appl.SearchItems().SearchFullText(ctx.Context, ctx.Q, &offset, &limit) count := int(c) if err != nil { cause := errs.Cause(err) switch cause.(type) { case errors.BadParameterError: jerrors, _ := jsonapi.ErrorToJSONAPIErrors(goa.ErrBadRequest(fmt.Sprintf("Error listing work items: %s", err.Error()))) return ctx.BadRequest(jerrors) default: log.Error(ctx, map[string]interface{}{ "err": err, }, "unable to list the work items") jerrors, _ := jsonapi.ErrorToJSONAPIErrors(goa.ErrInternal(err.Error())) return ctx.InternalServerError(jerrors) } } response := app.SearchWorkItemList{ Links: &app.PagingLinks{}, Meta: &app.WorkItemListResponseMeta{TotalCount: count}, Data: ConvertWorkItems(ctx.RequestData, result), } setPagingLinks(response.Links, buildAbsoluteURL(ctx.RequestData), len(result), offset, limit, count, "q="+ctx.Q) return ctx.OK(&response) }) }
// 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) }) }
// 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 }
// Show runs the show action. func (c *TrackerqueryController) Show(ctx *app.ShowTrackerqueryContext) error { return application.Transactional(c.db, func(appl application.Application) error { tq, err := appl.TrackerQueries().Load(ctx.Context, ctx.ID) if err != nil { cause := errs.Cause(err) switch cause.(type) { case remoteworkitem.NotFoundError: log.Error(ctx, map[string]interface{}{ "trackerID": ctx.ID, }, "tracker query controller not found") jerrors, _ := jsonapi.ErrorToJSONAPIErrors(goa.ErrNotFound(err.Error())) return ctx.NotFound(jerrors) default: return errs.WithStack(err) } } return ctx.OK(tq) }) }
// 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 }
// Show runs the show action. func (c *TrackerController) Show(ctx *app.ShowTrackerContext) error { return application.Transactional(c.db, func(appl application.Application) error { t, err := appl.Trackers().Load(ctx.Context, ctx.ID) if err != nil { cause := errs.Cause(err) switch cause.(type) { case remoteworkitem.NotFoundError: log.Error(ctx, map[string]interface{}{ "trackerID": ctx.ID, }, "tracker controller not found") jerrors, _ := jsonapi.ErrorToJSONAPIErrors(goa.ErrNotFound(err.Error())) return ctx.NotFound(jerrors) default: jerrors, httpStatusCode := jsonapi.ErrorToJSONAPIErrors(goa.ErrInternal(err.Error())) return ctx.ResponseData.Service.Send(ctx.Context, httpStatusCode, jerrors) } } return ctx.OK(t) }) }