diff --git a/Makefile b/Makefile index 6640c6d5c..f10c380dd 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ gen_template: go generate github.com/drone/drone/template gen_migrations: - go generate github.com/drone/drone/shared/database + go generate github.com/drone/drone/store/migration build: go build diff --git a/controller/user.go b/controller/user.go index 374d2b81c..69759f725 100644 --- a/controller/user.go +++ b/controller/user.go @@ -18,12 +18,28 @@ func GetSelf(c *gin.Context) { func GetFeed(c *gin.Context) { user := session.User(c) - feed, err := store.GetUserFeed(c, user, 25, 0) + remote := remote.FromContext(c) + var repos []*model.RepoLite + + // get the repository list from the cache + reposv, ok := c.Get("repos") + if ok { + repos = reposv.([]*model.RepoLite) + } else { + var err error + repos, err = remote.Repos(user) + if err != nil { + c.String(400, err.Error()) + return + } + } + + feed, err := store.GetUserFeed(c, repos) if err != nil { - c.AbortWithStatus(http.StatusInternalServerError) + c.String(400, err.Error()) return } - c.IndentedJSON(http.StatusOK, feed) + c.JSON(200, feed) } func GetRepos(c *gin.Context) { diff --git a/router/router.go b/router/router.go index a56fb1783..b1d3be577 100644 --- a/router/router.go +++ b/router/router.go @@ -62,7 +62,7 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { { user.Use(session.MustUser()) user.GET("", controller.GetSelf) - // user.GET("/builds", controller.GetFeed) + user.GET("/feed", controller.GetFeed) user.GET("/repos", cache.Repos, controller.GetRepos) user.GET("/repos/remote", cache.Repos, controller.GetRemoteRepos) user.POST("/token", controller.PostToken) diff --git a/store/datastore/repos.go b/store/datastore/repos.go index f1473f821..f71bfe5e7 100644 --- a/store/datastore/repos.go +++ b/store/datastore/repos.go @@ -2,7 +2,7 @@ package datastore import ( "database/sql" - "strings" + "fmt" "github.com/drone/drone/model" "github.com/russross/meddler" @@ -25,20 +25,18 @@ func (db *repostore) GetName(name string) (*model.Repo, error) { } func (db *repostore) GetListOf(listof []*model.RepoLite) ([]*model.Repo, error) { - var repos = []*model.Repo{} - var size = len(listof) - if size > 999 { - size = 999 - listof = listof[:999] + var ( + repos []*model.Repo + args []interface{} + stmt string + ) + switch meddler.Default { + case meddler.PostgreSQL: + stmt, args = toListPosgres(listof) + default: + stmt, args = toList(listof) } - var qs = make([]string, size, size) - var in = make([]interface{}, size, size) - for i, repo := range listof { - qs[i] = "?" - in[i] = repo.FullName - } - var stmt = "SELECT * FROM repos WHERE repo_full_name IN (" + strings.Join(qs, ",") + ") ORDER BY repo_name" - var err = meddler.QueryAll(db, &repos, rebind(stmt), in...) + err := meddler.QueryAll(db, &repos, fmt.Sprintf(repoListOfQuery, stmt), args...) return repos, err } @@ -81,6 +79,13 @@ WHERE repo_id IN ( ORDER BY repo_full_name ` +const repoListOfQuery = ` +SELECT * +FROM repos +WHERE repo_full_name IN (" + stmt + ") +ORDER BY repo_name +` + const repoCountQuery = ` SELECT COUNT(*) FROM repos ` diff --git a/store/datastore/users.go b/store/datastore/users.go index 9b6276c5c..41521006e 100644 --- a/store/datastore/users.go +++ b/store/datastore/users.go @@ -2,6 +2,7 @@ package datastore import ( "database/sql" + "fmt" "github.com/drone/drone/model" "github.com/russross/meddler" @@ -29,11 +30,20 @@ func (db *userstore) GetList() ([]*model.User, error) { return users, err } -func (db *userstore) GetFeed(user *model.User, limit, offset int) ([]*model.Feed, error) { - // var feed = []*Feed{} - // var err = meddler.QueryAll(db, &feed, rebind(userFeedQuery), user.Login, limit, offset) - // return feed, err - return nil, nil +func (db *userstore) GetFeed(listof []*model.RepoLite) ([]*model.Feed, error) { + var ( + feed []*model.Feed + args []interface{} + stmt string + ) + switch meddler.Default { + case meddler.PostgreSQL: + stmt, args = toListPosgres(listof) + default: + stmt, args = toList(listof) + } + err := meddler.QueryAll(db, &feed, fmt.Sprintf(userFeedQuery, stmt), args...) + return feed, err } func (db *userstore) Count() (int, error) { @@ -105,7 +115,7 @@ FROM builds b ,repos r WHERE b.build_repo_id = r.repo_id - AND b.build_author = ? + AND r.repo_full_name IN (%s) ORDER BY b.build_id DESC -LIMIT ? OFFSET ? +LIMIT 25 ` diff --git a/store/datastore/users_test.go b/store/datastore/users_test.go index 31e54ba10..0a4135799 100644 --- a/store/datastore/users_test.go +++ b/store/datastore/users_test.go @@ -164,46 +164,59 @@ func Test_userstore(t *testing.T) { g.Assert(err3 == nil).IsFalse() }) - // g.It("Should get the Build feed for a User", func() { - // repo1 := &Repo{ - // UserID: 1, - // Owner: "bradrydzewski", - // Name: "drone", - // FullName: "bradrydzewski/drone", - // } - // repo2 := &Repo{ - // UserID: 2, - // Owner: "drone", - // Name: "drone", - // FullName: "drone/drone", - // } - // CreateRepo(db, repo1) - // CreateRepo(db, repo2) + g.It("Should get the Build feed for a User", func() { + repo1 := &model.Repo{ + UserID: 1, + Owner: "bradrydzewski", + Name: "drone", + FullName: "bradrydzewski/drone", + } + repo2 := &model.Repo{ + UserID: 2, + Owner: "drone", + Name: "drone", + FullName: "drone/drone", + } + repo3 := &model.Repo{ + UserID: 2, + Owner: "octocat", + Name: "hello-world", + FullName: "octocat/hello-world", + } + s.Repos().Create(repo1) + s.Repos().Create(repo2) + s.Repos().Create(repo3) - // build1 := &Build{ - // RepoID: repo1.ID, - // Status: StatusFailure, - // Author: "bradrydzewski", - // } - // build2 := &Build{ - // RepoID: repo1.ID, - // Status: StatusSuccess, - // Author: "bradrydzewski", - // } - // build3 := &Build{ - // RepoID: repo2.ID, - // Status: StatusSuccess, - // Author: "octocat", - // } - // CreateBuild(db, build1) - // CreateBuild(db, build2) - // CreateBuild(db, build3) + build1 := &model.Build{ + RepoID: repo1.ID, + Status: model.StatusFailure, + } + build2 := &model.Build{ + RepoID: repo1.ID, + Status: model.StatusSuccess, + } + build3 := &model.Build{ + RepoID: repo2.ID, + Status: model.StatusSuccess, + } + build4 := &model.Build{ + RepoID: repo3.ID, + Status: model.StatusSuccess, + } + s.Builds().Create(build1) + s.Builds().Create(build2) + s.Builds().Create(build3) + s.Builds().Create(build4) - // builds, err := GetUserFeed(db, &User{ID: 1, Login: "bradrydzewski"}, 20, 0) - // g.Assert(err == nil).IsTrue() - // g.Assert(len(builds)).Equal(2) - // g.Assert(builds[0].Owner).Equal("bradrydzewski") - // g.Assert(builds[0].Name).Equal("drone") - // }) + builds, err := s.Users().GetFeed([]*model.RepoLite{ + {FullName: "bradrydzewski/drone"}, + {FullName: "drone/drone"}, + }) + g.Assert(err == nil).IsTrue() + g.Assert(len(builds)).Equal(3) + g.Assert(builds[0].FullName).Equal(repo2.FullName) + g.Assert(builds[1].FullName).Equal(repo1.FullName) + g.Assert(builds[2].FullName).Equal(repo1.FullName) + }) }) } diff --git a/store/datastore/utils.go b/store/datastore/utils.go index dbf0e8b75..fae7c2b2e 100644 --- a/store/datastore/utils.go +++ b/store/datastore/utils.go @@ -2,7 +2,9 @@ package datastore import ( "strconv" + "strings" + "github.com/drone/drone/model" "github.com/russross/meddler" ) @@ -33,3 +35,37 @@ func rebind(query string) string { } return string(rqb) } + +// helper function that converts a simple repsitory list +// to a sql IN statment. +func toList(listof []*model.RepoLite) (string, []interface{}) { + var size = len(listof) + if size > 999 { + size = 999 + listof = listof[:999] + } + var qs = make([]string, size, size) + var in = make([]interface{}, size, size) + for i, repo := range listof { + qs[i] = "$" + strconv.Itoa(i+1) + in[i] = repo.FullName + } + return strings.Join(qs, ","), in +} + +// helper function that converts a simple repsitory list +// to a sql IN statment compatible with postgres. +func toListPosgres(listof []*model.RepoLite) (string, []interface{}) { + var size = len(listof) + if size > 999 { + size = 999 + listof = listof[:999] + } + var qs = make([]string, size, size) + var in = make([]interface{}, size, size) + for i, repo := range listof { + qs[i] = "$" + strconv.Itoa(i+1) + in[i] = repo.FullName + } + return strings.Join(qs, ","), in +} diff --git a/store/users.go b/store/users.go index d1704eeff..e4d00d25b 100644 --- a/store/users.go +++ b/store/users.go @@ -16,7 +16,7 @@ type UserStore interface { GetList() ([]*model.User, error) // GetFeed gets a user activity feed. - GetFeed(*model.User, int, int) ([]*model.Feed, error) + GetFeed([]*model.RepoLite) ([]*model.Feed, error) // Count gets a count of all users in the system. Count() (int, error) @@ -43,8 +43,8 @@ func GetUserList(c context.Context) ([]*model.User, error) { return FromContext(c).Users().GetList() } -func GetUserFeed(c context.Context, user *model.User, limit, offset int) ([]*model.Feed, error) { - return FromContext(c).Users().GetFeed(user, limit, offset) +func GetUserFeed(c context.Context, listof []*model.RepoLite) ([]*model.Feed, error) { + return FromContext(c).Users().GetFeed(listof) } func CountUsers(c context.Context) (int, error) {