diff --git a/cache/cache.go b/cache/cache.go deleted file mode 100644 index 973e53898..000000000 --- a/cache/cache.go +++ /dev/null @@ -1,40 +0,0 @@ -package cache - -//go:generate mockery -name Cache -output mock -case=underscore - -import ( - "time" - - "github.com/koding/cache" - "golang.org/x/net/context" -) - -type Cache interface { - Get(string) (interface{}, error) - Set(string, interface{}) error - Delete(string) error -} - -func Get(c context.Context, key string) (interface{}, error) { - return FromContext(c).Get(key) -} - -func Set(c context.Context, key string, value interface{}) error { - return FromContext(c).Set(key, value) -} - -func Delete(c context.Context, key string) error { - return FromContext(c).Delete(key) -} - -// Default creates an in-memory cache with the default -// 30 minute expiration period. -func Default() Cache { - return NewTTL(time.Minute * 30) -} - -// NewTTL returns an in-memory cache with the specified -// ttl expiration period. -func NewTTL(t time.Duration) Cache { - return cache.NewMemoryWithTTL(t) -} diff --git a/cache/cache_test.go b/cache/cache_test.go deleted file mode 100644 index e984da2ce..000000000 --- a/cache/cache_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package cache - -import ( - "testing" - - "github.com/franela/goblin" - "github.com/gin-gonic/gin" -) - -func TestCache(t *testing.T) { - - g := goblin.Goblin(t) - g.Describe("Cache", func() { - - var c *gin.Context - g.BeforeEach(func() { - c = new(gin.Context) - ToContext(c, Default()) - }) - - g.It("Should set and get an item", func() { - Set(c, "foo", "bar") - v, e := Get(c, "foo") - g.Assert(v).Equal("bar") - g.Assert(e == nil).IsTrue() - }) - - g.It("Should return nil when item not found", func() { - v, e := Get(c, "foo") - g.Assert(v == nil).IsTrue() - g.Assert(e == nil).IsFalse() - }) - }) -} diff --git a/cache/context.go b/cache/context.go deleted file mode 100644 index 5fe513dbd..000000000 --- a/cache/context.go +++ /dev/null @@ -1,23 +0,0 @@ -package cache - -import ( - "golang.org/x/net/context" -) - -const key = "cache" - -// Setter defines a context that enables setting values. -type Setter interface { - Set(string, interface{}) -} - -// FromContext returns the Cache associated with this context. -func FromContext(c context.Context) Cache { - return c.Value(key).(Cache) -} - -// ToContext adds the Cache to this context if it supports -// the Setter interface. -func ToContext(c Setter, cache Cache) { - c.Set(key, cache) -} diff --git a/cache/helper.go b/cache/helper.go deleted file mode 100644 index c39fbd60a..000000000 --- a/cache/helper.go +++ /dev/null @@ -1,99 +0,0 @@ -package cache - -import ( - "fmt" - - "github.com/drone/drone/model" - "github.com/drone/drone/remote" - "golang.org/x/net/context" -) - -// GetPerms returns the user permissions repositories from the cache -// associated with the current repository. -func GetPerms(c context.Context, user *model.User, owner, name string) (*model.Perm, error) { - key := fmt.Sprintf("perms:%s:%s/%s", - user.Login, - owner, - name, - ) - // if we fetch from the cache we can return immediately - val, err := Get(c, key) - if err == nil { - return val.(*model.Perm), nil - } - // else we try to grab from the remote system and - // populate our cache. - perm, err := remote.Perm(c, user, owner, name) - if err != nil { - return nil, err - } - Set(c, key, perm) - return perm, nil -} - -// GetTeamPerms returns the user permissions from the cache -// associated with the current organization. -func GetTeamPerms(c context.Context, user *model.User, org string) (*model.Perm, error) { - key := fmt.Sprintf("perms:%s:%s", - user.Login, - org, - ) - // if we fetch from the cache we can return immediately - val, err := Get(c, key) - if err == nil { - return val.(*model.Perm), nil - } - // else we try to grab from the remote system and - // populate our cache. - perm, err := remote.TeamPerm(c, user, org) - if err != nil { - return nil, err - } - Set(c, key, perm) - return perm, nil -} - -// GetRepos returns the list of user repositories from the cache -// associated with the current context. -func GetRepos(c context.Context, user *model.User) ([]*model.RepoLite, error) { - key := fmt.Sprintf("repos:%s", - user.Login, - ) - // if we fetch from the cache we can return immediately - val, err := Get(c, key) - if err == nil { - return val.([]*model.RepoLite), nil - } - // else we try to grab from the remote system and - // populate our cache. - repos, err := remote.Repos(c, user) - if err != nil { - return nil, err - } - - Set(c, key, repos) - return repos, nil -} - -// GetRepoMap returns the list of user repositories from the cache -// associated with the current context in a map structure. -func GetRepoMap(c context.Context, user *model.User) (map[string]bool, error) { - repos, err := GetRepos(c, user) - if err != nil { - return nil, err - } - repom := map[string]bool{} - for _, repo := range repos { - repom[repo.FullName] = true - } - return repom, nil -} - -// DeleteRepos evicts the cached user repositories from the cache associated -// with the current context. -func DeleteRepos(c context.Context, user *model.User) error { - key := fmt.Sprintf("repos:%s", - user.Login, - ) - return Delete(c, key) -} diff --git a/cache/helper_test.go b/cache/helper_test.go deleted file mode 100644 index f0bd53ab1..000000000 --- a/cache/helper_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package cache - -import ( - "errors" - "fmt" - "testing" - - "github.com/drone/drone/model" - "github.com/drone/drone/remote" - "github.com/drone/drone/remote/mock" - "github.com/franela/goblin" - "github.com/gin-gonic/gin" -) - -func TestHelper(t *testing.T) { - - g := goblin.Goblin(t) - - g.Describe("Cache helpers", func() { - - var c *gin.Context - var r *mock.Remote - - g.BeforeEach(func() { - c = new(gin.Context) - ToContext(c, Default()) - - r = new(mock.Remote) - remote.ToContext(c, r) - }) - - g.It("Should get permissions from remote", func() { - r.On("Perm", fakeUser, fakeRepo.Owner, fakeRepo.Name).Return(fakePerm, nil).Once() - p, err := GetPerms(c, fakeUser, fakeRepo.Owner, fakeRepo.Name) - g.Assert(p).Equal(fakePerm) - g.Assert(err).Equal(nil) - - }) - - g.It("Should get permissions from cache", func() { - key := fmt.Sprintf("perms:%s:%s/%s", - fakeUser.Login, - fakeRepo.Owner, - fakeRepo.Name, - ) - - Set(c, key, fakePerm) - r.On("Perm", fakeUser, fakeRepo.Owner, fakeRepo.Name).Return(nil, fakeErr).Once() - p, err := GetPerms(c, fakeUser, fakeRepo.Owner, fakeRepo.Name) - g.Assert(p).Equal(fakePerm) - g.Assert(err).Equal(nil) - }) - - g.It("Should get permissions error", func() { - r.On("Perm", fakeUser, fakeRepo.Owner, fakeRepo.Name).Return(nil, fakeErr).Once() - p, err := GetPerms(c, fakeUser, fakeRepo.Owner, fakeRepo.Name) - g.Assert(p == nil).IsTrue() - g.Assert(err).Equal(fakeErr) - }) - - g.It("Should set and get repos", func() { - - r.On("Repos", fakeUser).Return(fakeRepos, nil).Once() - p, err := GetRepos(c, fakeUser) - g.Assert(p).Equal(fakeRepos) - g.Assert(err).Equal(nil) - }) - - g.It("Should get repos", func() { - key := fmt.Sprintf("repos:%s", - fakeUser.Login, - ) - - Set(c, key, fakeRepos) - r.On("Repos", fakeUser).Return(nil, fakeErr).Once() - p, err := GetRepos(c, fakeUser) - g.Assert(p).Equal(fakeRepos) - g.Assert(err).Equal(nil) - }) - - g.It("Should get repos error", func() { - r.On("Repos", fakeUser).Return(nil, fakeErr).Once() - p, err := GetRepos(c, fakeUser) - g.Assert(p == nil).IsTrue() - g.Assert(err).Equal(fakeErr) - }) - - g.It("Should evict repos", func() { - key := fmt.Sprintf("repos:%s", - fakeUser.Login, - ) - - Set(c, key, fakeRepos) - repos, err := Get(c, key) - g.Assert(repos != nil).IsTrue() - g.Assert(err == nil).IsTrue() - - DeleteRepos(c, fakeUser) - repos, err = Get(c, key) - g.Assert(repos == nil).IsTrue() - }) - }) -} - -var ( - fakeErr = errors.New("Not Found") - fakeUser = &model.User{Login: "octocat"} - fakePerm = &model.Perm{true, true, true} - fakeRepo = &model.RepoLite{Owner: "octocat", Name: "Hello-World"} - fakeRepos = []*model.RepoLite{ - {Owner: "octocat", Name: "Hello-World"}, - {Owner: "octocat", Name: "hello-world"}, - {Owner: "octocat", Name: "Spoon-Knife"}, - } -) diff --git a/cmd/drone-server/server.go b/cmd/drone-server/server.go index 0aba053c8..46bfaaa48 100644 --- a/cmd/drone-server/server.go +++ b/cmd/drone-server/server.go @@ -80,12 +80,6 @@ var flags = []cli.Flag{ Name: "open", Usage: "open user registration", }, - cli.DurationFlag{ - EnvVar: "DRONE_CACHE_TTL", - Name: "cache-ttl", - Usage: "cache duration", - Value: time.Minute * 15, - }, cli.StringSliceFlag{ EnvVar: "DRONE_ESCALATE", Name: "escalate", @@ -415,7 +409,6 @@ func server(c *cli.Context) error { ginrus.Ginrus(logrus.StandardLogger(), time.RFC3339, true), middleware.Version, middleware.Config(c), - middleware.Cache(c), middleware.Store(c, store_), middleware.Remote(remote_), ) diff --git a/model/perm.go b/model/perm.go index 2e8054658..f0aa5e184 100644 --- a/model/perm.go +++ b/model/perm.go @@ -1,7 +1,21 @@ package model -type Perm struct { - Pull bool `json:"pull"` - Push bool `json:"push"` - Admin bool `json:"admin"` +// PermStore persists repository permissions information to storage. +type PermStore interface { + PermFind(user *User, repo *Repo) (*Perm, error) + PermUpsert(perm *Perm) error + PermBatch(perms []*Perm) error + PermDelete(perm *Perm) error + PermFlush(user *User, before int64) error +} + +// Perm defines a repository permission for an individual user. +type Perm struct { + UserID int64 `json:"-" meddler:"perm_user_id"` + RepoID int64 `json:"-" meddler:"perm_repo_id"` + Repo string `json:"-" meddler:"-"` + Pull bool `json:"pull" meddler:"perm_pull"` + Push bool `json:"push" meddler:"perm_push"` + Admin bool `json:"admin" meddler:"perm_admin"` + Synced int64 `json:"synced" meddler:"perm_synced"` } diff --git a/model/repo.go b/model/repo.go index 4ef2157a6..a59239a18 100644 --- a/model/repo.go +++ b/model/repo.go @@ -27,6 +27,7 @@ type Repo struct { IsTrusted bool `json:"trusted" meddler:"repo_trusted"` IsStarred bool `json:"starred,omitempty" meddler:"-"` IsGated bool `json:"gated" meddler:"repo_gated"` + IsActive bool `json:"active,omitempty" meddler:"repo_active"` AllowPull bool `json:"allow_pr" meddler:"repo_allow_pr"` AllowPush bool `json:"allow_push" meddler:"repo_allow_push"` AllowDeploy bool `json:"allow_deploys" meddler:"repo_allow_deploys"` @@ -34,6 +35,7 @@ type Repo struct { Counter int `json:"last_build" meddler:"repo_counter"` Config string `json:"config_file" meddler:"repo_config_path"` Hash string `json:"-" meddler:"repo_hash"` + Perm *Perm `json:"-" meddler:"-"` } // RepoPatch represents a repository patch object. diff --git a/model/user.go b/model/user.go index fdd46168a..4f844a1c3 100644 --- a/model/user.go +++ b/model/user.go @@ -34,6 +34,9 @@ type User struct { // Activate indicates the user is active in the system. Active bool `json:"active" meddler:"user_active"` + // Synced is the timestamp when the user was synced with the remote system. + Synced int64 `json:"synced" meddler:"user_synced"` + // Admin indicates the user is a system administrator. // // NOTE: This is sourced from the DRONE_ADMINS environment variable and is no diff --git a/remote/bitbucket/bitbucket.go b/remote/bitbucket/bitbucket.go index 736f8882a..3632fa262 100644 --- a/remote/bitbucket/bitbucket.go +++ b/remote/bitbucket/bitbucket.go @@ -114,11 +114,6 @@ func (c *config) Teams(u *model.User) ([]*model.Team, error) { return convertTeamList(resp.Values), nil } -// TeamPerm is not supported by the Bitbucket driver. -func (c *config) TeamPerm(u *model.User, org string) (*model.Perm, error) { - return nil, nil -} - // Repo returns the named Bitbucket repository. func (c *config) Repo(u *model.User, owner, name string) (*model.Repo, error) { repo, err := c.newClient(u).FindRepo(owner, name) @@ -130,10 +125,10 @@ func (c *config) Repo(u *model.User, owner, name string) (*model.Repo, error) { // Repos returns a list of all repositories for Bitbucket account, including // organization repositories. -func (c *config) Repos(u *model.User) ([]*model.RepoLite, error) { +func (c *config) Repos(u *model.User) ([]*model.Repo, error) { client := c.newClient(u) - var all []*model.RepoLite + var all []*model.Repo accounts := []string{u.Login} resp, err := client.ListTeams(&internal.ListTeamOpts{ @@ -153,7 +148,7 @@ func (c *config) Repos(u *model.User) ([]*model.RepoLite, error) { return all, err } for _, repo := range repos { - all = append(all, convertRepoLite(repo)) + all = append(all, convertRepo(repo)) } } return all, nil diff --git a/remote/bitbucket/convert.go b/remote/bitbucket/convert.go index b5272b409..b5627bc71 100644 --- a/remote/bitbucket/convert.go +++ b/remote/bitbucket/convert.go @@ -110,17 +110,6 @@ func cloneLink(repo *internal.Repo) string { return clone } -// convertRepoLite is a helper function used to convert a Bitbucket repository -// structure to the simplified Drone repository structure. -func convertRepoLite(from *internal.Repo) *model.RepoLite { - return &model.RepoLite{ - Owner: strings.Split(from.FullName, "/")[0], - Name: strings.Split(from.FullName, "/")[1], - FullName: from.FullName, - Avatar: from.Owner.Links.Avatar.Href, - } -} - // convertUser is a helper function used to convert a Bitbucket user account // structure to the Drone User structure. func convertUser(from *internal.Account, token *oauth2.Token) *model.User { diff --git a/remote/bitbucket/convert_test.go b/remote/bitbucket/convert_test.go index 50b552374..74903f5c6 100644 --- a/remote/bitbucket/convert_test.go +++ b/remote/bitbucket/convert_test.go @@ -49,18 +49,6 @@ func Test_helper(t *testing.T) { g.Assert(convertDesc(model.StatusError)).Equal(descError) }) - g.It("should convert repository lite", func() { - from := &internal.Repo{} - from.FullName = "octocat/hello-world" - from.Owner.Links.Avatar.Href = "http://..." - - to := convertRepoLite(from) - g.Assert(to.Avatar).Equal(from.Owner.Links.Avatar.Href) - g.Assert(to.FullName).Equal(from.FullName) - g.Assert(to.Owner).Equal("octocat") - g.Assert(to.Name).Equal("hello-world") - }) - g.It("should convert repository", func() { from := &internal.Repo{ FullName: "octocat/hello-world", diff --git a/remote/bitbucketserver/bitbucketserver.go b/remote/bitbucketserver/bitbucketserver.go index b8c7e2324..b041b5ce4 100644 --- a/remote/bitbucketserver/bitbucketserver.go +++ b/remote/bitbucketserver/bitbucketserver.go @@ -140,14 +140,14 @@ func (c *Config) Repo(u *model.User, owner, name string) (*model.Repo, error) { return convertRepo(repo), nil } -func (c *Config) Repos(u *model.User) ([]*model.RepoLite, error) { +func (c *Config) Repos(u *model.User) ([]*model.Repo, error) { repos, err := internal.NewClientWithToken(c.URL, c.Consumer, u.Token).FindRepos() if err != nil { return nil, err } - var all []*model.RepoLite + var all []*model.Repo for _, repo := range repos { - all = append(all, convertRepoLite(repo)) + all = append(all, convertRepo(repo)) } return all, nil @@ -233,7 +233,7 @@ func CreateConsumer(URL string, ConsumerKey string, PrivateKey *rsa.PrivateKey) consumer.HttpClient = &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - Proxy: http.ProxyFromEnvironment, + Proxy: http.ProxyFromEnvironment, }, } return consumer diff --git a/remote/bitbucketserver/convert.go b/remote/bitbucketserver/convert.go index 7d1416224..cf1f6b71a 100644 --- a/remote/bitbucketserver/convert.go +++ b/remote/bitbucketserver/convert.go @@ -86,19 +86,6 @@ func convertRepo(from *internal.Repo) *model.Repo { } -// convertRepoLite is a helper function used to convert a Bitbucket repository -// structure to the simplified Drone repository structure. -func convertRepoLite(from *internal.Repo) *model.RepoLite { - return &model.RepoLite{ - Owner: from.Project.Key, - Name: from.Slug, - FullName: from.Project.Key + "/" + from.Slug, - //TODO: find the avatar for the repo - //Avatar: might need another ws call? - } - -} - // convertPushHook is a helper function used to convert a Bitbucket push // hook to the Drone build struct holding commit information. func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build { diff --git a/remote/bitbucketserver/convert_test.go b/remote/bitbucketserver/convert_test.go index 9c0a41536..2860d601f 100644 --- a/remote/bitbucketserver/convert_test.go +++ b/remote/bitbucketserver/convert_test.go @@ -1,11 +1,12 @@ package bitbucketserver import ( + "testing" + "github.com/drone/drone/model" "github.com/drone/drone/remote/bitbucketserver/internal" "github.com/franela/goblin" "github.com/mrjones/oauth" - "testing" ) func Test_helper(t *testing.T) { @@ -13,17 +14,6 @@ func Test_helper(t *testing.T) { g := goblin.Goblin(t) g.Describe("Bitbucket Server converter", func() { - g.It("should convert repository lite", func() { - from := &internal.Repo{} - from.Project.Key = "octocat" - from.Slug = "hello-world" - - to := convertRepoLite(from) - g.Assert(to.FullName).Equal("octocat/hello-world") - g.Assert(to.Owner).Equal("octocat") - g.Assert(to.Name).Equal("hello-world") - }) - g.It("should convert repository", func() { from := &internal.Repo{ Slug: "hello-world", diff --git a/remote/gerrit/gerrit.go b/remote/gerrit/gerrit.go index 4554e3ffe..4ddc6a32b 100644 --- a/remote/gerrit/gerrit.go +++ b/remote/gerrit/gerrit.go @@ -69,18 +69,13 @@ func (c *client) Teams(u *model.User) ([]*model.Team, error) { return empty, nil } -// TeamPerm is not supported by the Gerrit driver. -func (c *client) TeamPerm(u *model.User, org string) (*model.Perm, error) { - return nil, nil -} - // Repo is not supported by the Gerrit driver. func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) { return nil, nil } // Repos is not supported by the Gerrit driver. -func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) { +func (c *client) Repos(u *model.User) ([]*model.Repo, error) { return nil, nil } diff --git a/remote/gitea/gitea.go b/remote/gitea/gitea.go index 29fd80ef7..af2c56852 100644 --- a/remote/gitea/gitea.go +++ b/remote/gitea/gitea.go @@ -200,8 +200,8 @@ func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) { // Repos returns a list of all repositories for the Gitea account, including // organization repositories. -func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) { - repos := []*model.RepoLite{} +func (c *client) Repos(u *model.User) ([]*model.Repo, error) { + repos := []*model.Repo{} client := c.newClientToken(u.Token) all, err := client.ListMyRepos() @@ -210,7 +210,7 @@ func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) { } for _, repo := range all { - repos = append(repos, toRepoLite(repo)) + repos = append(repos, toRepo(repo)) } return repos, err } diff --git a/remote/gitea/helper.go b/remote/gitea/helper.go index e0674dc8a..ead57c052 100644 --- a/remote/gitea/helper.go +++ b/remote/gitea/helper.go @@ -12,21 +12,6 @@ import ( "github.com/drone/drone/model" ) -// helper function that converts a Gitea repository to a Drone repository. -func toRepoLite(from *gitea.Repository) *model.RepoLite { - name := strings.Split(from.FullName, "/")[1] - avatar := expandAvatar( - from.HTMLURL, - from.Owner.AvatarURL, - ) - return &model.RepoLite{ - Name: name, - Owner: from.Owner.UserName, - FullName: from.FullName, - Avatar: avatar, - } -} - // helper function that converts a Gitea repository to a Drone repository. func toRepo(from *gitea.Repository) *model.Repo { name := strings.Split(from.FullName, "/")[1] diff --git a/remote/gitea/helper_test.go b/remote/gitea/helper_test.go index fa1332cb1..ca01ffe45 100644 --- a/remote/gitea/helper_test.go +++ b/remote/gitea/helper_test.go @@ -177,21 +177,6 @@ func Test_parse(t *testing.T) { g.Assert(repo.IsPrivate).Equal(from.Private) }) - g.It("Should return a RepoLite struct from a Gitea Repo", func() { - from := gitea.Repository{ - FullName: "gophers/hello-world", - Owner: &gitea.User{ - UserName: "gordon", - AvatarURL: "http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87", - }, - } - repo := toRepoLite(&from) - g.Assert(repo.FullName).Equal(from.FullName) - g.Assert(repo.Owner).Equal(from.Owner.UserName) - g.Assert(repo.Name).Equal("hello-world") - g.Assert(repo.Avatar).Equal(from.Owner.AvatarURL) - }) - g.It("Should correct a malformed avatar url", func() { var urls = []struct { diff --git a/remote/github/convert.go b/remote/github/convert.go index ade900384..f961b7e4f 100644 --- a/remote/github/convert.go +++ b/remote/github/convert.go @@ -80,6 +80,7 @@ func convertRepo(from *github.Repository, private bool) *model.Repo { Avatar: *from.Owner.AvatarURL, Kind: model.RepoGit, Branch: defaultBranch, + Perm: convertPerm(from), } if from.DefaultBranch != nil { repo.Branch = *from.DefaultBranch @@ -114,24 +115,24 @@ func convertTeamPerm(from *github.Membership) *model.Perm { // convertRepoList is a helper function used to convert a GitHub repository // list to the common Drone repository structure. -func convertRepoList(from []github.Repository) []*model.RepoLite { - var repos []*model.RepoLite +func convertRepoList(from []github.Repository, private bool) []*model.Repo { + var repos []*model.Repo for _, repo := range from { - repos = append(repos, convertRepoLite(repo)) + repos = append(repos, convertRepo(&repo, private)) } return repos } -// convertRepoLite is a helper function used to convert a GitHub repository -// structure to the common Drone repository structure. -func convertRepoLite(from github.Repository) *model.RepoLite { - return &model.RepoLite{ - Owner: *from.Owner.Login, - Name: *from.Name, - FullName: *from.FullName, - Avatar: *from.Owner.AvatarURL, - } -} +// // convertRepoLite is a helper function used to convert a GitHub repository +// // structure to the common Drone repository structure. +// func convertRepoLite(from github.Repository) *model.RepoLite { +// return &model.RepoLite{ +// Owner: *from.Owner.Login, +// Name: *from.Name, +// FullName: *from.FullName, +// Avatar: *from.Owner.AvatarURL, +// } +// } // convertTeamList is a helper function used to convert a GitHub team list to // the common Drone repository structure. diff --git a/remote/github/convert_test.go b/remote/github/convert_test.go index 3fc8b8e4c..1d5be07f5 100644 --- a/remote/github/convert_test.go +++ b/remote/github/convert_test.go @@ -50,36 +50,27 @@ func Test_helper(t *testing.T) { g.Assert(convertDesc(model.StatusError)).Equal(descError) }) - g.It("should convert repository lite", func() { - from := github.Repository{ - FullName: github.String("octocat/hello-world"), - Name: github.String("hello-world"), - Owner: &github.User{ - AvatarURL: github.String("http://..."), - Login: github.String("octocat"), - }, - } - - to := convertRepoLite(from) - g.Assert(to.Avatar).Equal("http://...") - g.Assert(to.FullName).Equal("octocat/hello-world") - g.Assert(to.Owner).Equal("octocat") - g.Assert(to.Name).Equal("hello-world") - }) - g.It("should convert repository list", func() { from := []github.Repository{ { + Private: github.Bool(false), FullName: github.String("octocat/hello-world"), Name: github.String("hello-world"), Owner: &github.User{ AvatarURL: github.String("http://..."), Login: github.String("octocat"), }, + HTMLURL: github.String("https://github.com/octocat/hello-world"), + CloneURL: github.String("https://github.com/octocat/hello-world.git"), + Permissions: &map[string]bool{ + "push": true, + "pull": true, + "admin": true, + }, }, } - to := convertRepoList(from) + to := convertRepoList(from, false) g.Assert(to[0].Avatar).Equal("http://...") g.Assert(to[0].FullName).Equal("octocat/hello-world") g.Assert(to[0].Owner).Equal("octocat") @@ -98,6 +89,11 @@ func Test_helper(t *testing.T) { AvatarURL: github.String("http://..."), Login: github.String("octocat"), }, + Permissions: &map[string]bool{ + "push": true, + "pull": true, + "admin": true, + }, } to := convertRepo(&from, false) diff --git a/remote/github/github.go b/remote/github/github.go index ba3468f61..097c8e758 100644 --- a/remote/github/github.go +++ b/remote/github/github.go @@ -168,16 +168,6 @@ func (c *client) Teams(u *model.User) ([]*model.Team, error) { return teams, nil } -// TeamPerm returns the user permissions for the named GitHub organization. -func (c *client) TeamPerm(u *model.User, org string) (*model.Perm, error) { - client := c.newClientToken(u.Token) - membership, _, err := client.Organizations.GetOrgMembership(u.Login, org) - if err != nil { - return nil, err - } - return convertTeamPerm(membership), nil -} - // Repo returns the named GitHub repository. func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) { client := c.newClientToken(u.Token) @@ -190,20 +180,20 @@ func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) { // Repos returns a list of all repositories for GitHub account, including // organization repositories. -func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) { +func (c *client) Repos(u *model.User) ([]*model.Repo, error) { client := c.newClientToken(u.Token) opts := new(github.RepositoryListOptions) opts.PerPage = 100 opts.Page = 1 - var repos []*model.RepoLite + var repos []*model.Repo for opts.Page > 0 { list, resp, err := client.Repositories.List("", opts) if err != nil { return nil, err } - repos = append(repos, convertRepoList(list)...) + repos = append(repos, convertRepoList(list, c.PrivateMode)...) opts.Page = resp.NextPage } return repos, nil diff --git a/remote/github/github_test.go b/remote/github/github_test.go index 8ba0a949b..bada35cda 100644 --- a/remote/github/github_test.go +++ b/remote/github/github_test.go @@ -110,23 +110,6 @@ func Test_github(t *testing.T) { }) }) - g.Describe("Requesting organization permissions", func() { - g.It("Should return the permission details of an admin", func() { - perm, err := c.TeamPerm(fakeUser, "octocat") - g.Assert(err == nil).IsTrue() - g.Assert(perm.Admin).IsTrue() - }) - g.It("Should return the permission details of a member", func() { - perm, err := c.TeamPerm(fakeUser, "github") - g.Assert(err == nil).IsTrue() - g.Assert(perm.Admin).IsFalse() - }) - g.It("Should handle a not found error", func() { - _, err := c.TeamPerm(fakeUser, "org_not_found") - g.Assert(err != nil).IsTrue() - }) - }) - g.It("Should return a user repository list") g.It("Should return a user team list") diff --git a/remote/gitlab/gitlab.go b/remote/gitlab/gitlab.go index 97e5eb772..6b088b4da 100644 --- a/remote/gitlab/gitlab.go +++ b/remote/gitlab/gitlab.go @@ -203,11 +203,6 @@ func (g *Gitlab) Teams(u *model.User) ([]*model.Team, error) { return teams, nil } -// TeamPerm is not supported by the Gitlab driver. -func (g *Gitlab) TeamPerm(u *model.User, org string) (*model.Perm, error) { - return nil, nil -} - // Repo fetches the named repository from the remote system. func (g *Gitlab) Repo(u *model.User, owner, name string) (*model.Repo, error) { client := NewClient(g.URL, u.Token, g.SkipVerify) @@ -248,32 +243,40 @@ func (g *Gitlab) Repo(u *model.User, owner, name string) (*model.Repo, error) { } // Repos fetches a list of repos from the remote system. -func (g *Gitlab) Repos(u *model.User) ([]*model.RepoLite, error) { +func (g *Gitlab) Repos(u *model.User) ([]*model.Repo, error) { client := NewClient(g.URL, u.Token, g.SkipVerify) - var repos = []*model.RepoLite{} + var repos = []*model.Repo{} all, err := client.AllProjects(g.HideArchives) if err != nil { return repos, err } - for _, repo := range all { - var parts = strings.Split(repo.PathWithNamespace, "/") + for _, repo_ := range all { + var parts = strings.Split(repo_.PathWithNamespace, "/") var owner = parts[0] var name = parts[1] - var avatar = repo.AvatarUrl - if len(avatar) != 0 && !strings.HasPrefix(avatar, "http") { - avatar = fmt.Sprintf("%s/%s", g.URL, avatar) + repo := &model.Repo{} + repo.Owner = owner + repo.Name = name + repo.FullName = repo_.PathWithNamespace + repo.Link = repo_.Url + repo.Clone = repo_.HttpRepoUrl + repo.Branch = "master" + + if repo_.DefaultBranch != "" { + repo.Branch = repo_.DefaultBranch } - repos = append(repos, &model.RepoLite{ - Owner: owner, - Name: name, - FullName: repo.PathWithNamespace, - Avatar: avatar, - }) + if g.PrivateMode { + repo.IsPrivate = true + } else { + repo.IsPrivate = !repo_.Public + } + + repos = append(repos, repo) } return repos, err @@ -295,7 +298,7 @@ func (g *Gitlab) Perm(u *model.User, owner, name string) (*model.Perm, error) { // repo owner is granted full access if repo.Owner != nil && repo.Owner.Username == u.Login { - return &model.Perm{true, true, true}, nil + return &model.Perm{Push: true, Pull: true, Admin: true}, nil } // check permission for current user diff --git a/remote/gogs/gogs.go b/remote/gogs/gogs.go index 85292ac9a..d3de92d08 100644 --- a/remote/gogs/gogs.go +++ b/remote/gogs/gogs.go @@ -127,11 +127,6 @@ func (c *client) Teams(u *model.User) ([]*model.Team, error) { return teams, nil } -// TeamPerm is not supported by the Gogs driver. -func (c *client) TeamPerm(u *model.User, org string) (*model.Perm, error) { - return nil, nil -} - // Repo returns the named Gogs repository. func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) { client := c.newClientToken(u.Token) @@ -147,8 +142,8 @@ func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) { // Repos returns a list of all repositories for the Gogs account, including // organization repositories. -func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) { - repos := []*model.RepoLite{} +func (c *client) Repos(u *model.User) ([]*model.Repo, error) { + repos := []*model.Repo{} client := c.newClientToken(u.Token) all, err := client.ListMyRepos() @@ -157,7 +152,7 @@ func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) { } for _, repo := range all { - repos = append(repos, toRepoLite(repo)) + repos = append(repos, toRepo(repo)) } return repos, err } diff --git a/remote/gogs/helper.go b/remote/gogs/helper.go index e85ba780e..ff62abcfd 100644 --- a/remote/gogs/helper.go +++ b/remote/gogs/helper.go @@ -12,21 +12,6 @@ import ( "github.com/gogits/go-gogs-client" ) -// helper function that converts a Gogs repository to a Drone repository. -func toRepoLite(from *gogs.Repository) *model.RepoLite { - name := strings.Split(from.FullName, "/")[1] - avatar := expandAvatar( - from.HtmlUrl, - from.Owner.AvatarUrl, - ) - return &model.RepoLite{ - Name: name, - Owner: from.Owner.UserName, - FullName: from.FullName, - Avatar: avatar, - } -} - // helper function that converts a Gogs repository to a Drone repository. func toRepo(from *gogs.Repository) *model.Repo { name := strings.Split(from.FullName, "/")[1] diff --git a/remote/gogs/helper_test.go b/remote/gogs/helper_test.go index f8ad2f4e0..4af534bb4 100644 --- a/remote/gogs/helper_test.go +++ b/remote/gogs/helper_test.go @@ -176,21 +176,6 @@ func Test_parse(t *testing.T) { g.Assert(repo.IsPrivate).Equal(from.Private) }) - g.It("Should return a RepoLite struct from a Gogs Repo", func() { - from := gogs.Repository{ - FullName: "gophers/hello-world", - Owner: gogs.User{ - UserName: "gordon", - AvatarUrl: "http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87", - }, - } - repo := toRepoLite(&from) - g.Assert(repo.FullName).Equal(from.FullName) - g.Assert(repo.Owner).Equal(from.Owner.UserName) - g.Assert(repo.Name).Equal("hello-world") - g.Assert(repo.Avatar).Equal(from.Owner.AvatarUrl) - }) - g.It("Should correct a malformed avatar url", func() { var urls = []struct { diff --git a/remote/remote.go b/remote/remote.go index ea7d0ec06..bdd441fcc 100644 --- a/remote/remote.go +++ b/remote/remote.go @@ -23,15 +23,11 @@ type Remote interface { // Teams fetches a list of team memberships from the remote system. Teams(u *model.User) ([]*model.Team, error) - // TeamPerm fetches the named organization permissions from - // the remote system for the specified user. - TeamPerm(u *model.User, org string) (*model.Perm, error) - // Repo fetches the named repository from the remote system. Repo(u *model.User, owner, repo string) (*model.Repo, error) // Repos fetches a list of repos from the remote system. - Repos(u *model.User) ([]*model.RepoLite, error) + Repos(u *model.User) ([]*model.Repo, error) // Perm fetches the named repository permissions from // the remote system for the specified user. @@ -89,19 +85,13 @@ func Teams(c context.Context, u *model.User) ([]*model.Team, error) { return FromContext(c).Teams(u) } -// TeamPerm fetches the named organization permissions from -// the remote system for the specified user. -func TeamPerm(c context.Context, u *model.User, org string) (*model.Perm, error) { - return FromContext(c).TeamPerm(u, org) -} - // Repo fetches the named repository from the remote system. func Repo(c context.Context, u *model.User, owner, repo string) (*model.Repo, error) { return FromContext(c).Repo(u, owner, repo) } // Repos fetches a list of repos from the remote system. -func Repos(c context.Context, u *model.User) ([]*model.RepoLite, error) { +func Repos(c context.Context, u *model.User) ([]*model.Repo, error) { return FromContext(c).Repos(u) } diff --git a/router/middleware/cache.go b/router/middleware/cache.go deleted file mode 100644 index 7f09d5f8e..000000000 --- a/router/middleware/cache.go +++ /dev/null @@ -1,24 +0,0 @@ -package middleware - -import ( - "github.com/drone/drone/cache" - - "github.com/gin-gonic/gin" - "github.com/urfave/cli" -) - -// Cache is a middleware function that initializes the Cache and attaches to -// the context of every http.Request. -func Cache(cli *cli.Context) gin.HandlerFunc { - v := setupCache(cli) - return func(c *gin.Context) { - cache.ToContext(c, v) - } -} - -// helper function to create the cache from the CLI context. -func setupCache(c *cli.Context) cache.Cache { - return cache.NewTTL( - c.Duration("cache-ttl"), - ) -} diff --git a/router/middleware/session/repo.go b/router/middleware/session/repo.go index 24c6d5790..6c69bb68e 100644 --- a/router/middleware/session/repo.go +++ b/router/middleware/session/repo.go @@ -2,9 +2,10 @@ package session import ( "net/http" + "time" - "github.com/drone/drone/cache" "github.com/drone/drone/model" + "github.com/drone/drone/remote" "github.com/drone/drone/store" log "github.com/Sirupsen/logrus" @@ -92,10 +93,20 @@ func SetPerm() gin.HandlerFunc { case user != nil: var err error - perm, err = cache.GetPerms(c, user, repo.Owner, repo.Name) + perm, err = store.FromContext(c).PermFind(user, repo) if err != nil { - log.Errorf("Error fetching permission for %s %s", - user.Login, repo.FullName) + log.Errorf("Error fetching permission for %s %s. %s", + user.Login, repo.FullName, err) + } + if time.Unix(perm.Synced, 0).Add(time.Hour).Before(time.Now()) { + perm, err = remote.FromContext(c).Perm(user, repo.Owner, repo.Name) + if err == nil { + log.Debugf("Synced user permission for %s %s", user.Login, repo.FullName) + perm.Repo = repo.FullName + perm.UserID = user.ID + perm.Synced = time.Now().Unix() + store.FromContext(c).PermUpsert(perm) + } } } diff --git a/router/middleware/session/team.go b/router/middleware/session/team.go deleted file mode 100644 index f848564af..000000000 --- a/router/middleware/session/team.go +++ /dev/null @@ -1,73 +0,0 @@ -package session - -import ( - "github.com/drone/drone/cache" - "github.com/drone/drone/model" - - log "github.com/Sirupsen/logrus" - "github.com/gin-gonic/gin" -) - -func TeamPerm(c *gin.Context) *model.Perm { - user := User(c) - team := c.Param("team") - perm := &model.Perm{} - - switch { - // if the user is not authenticated - case user == nil: - perm.Admin = false - perm.Pull = false - perm.Push = false - - // if the user is a DRONE_ADMIN - case user.Admin: - perm.Admin = true - perm.Pull = true - perm.Push = true - - // otherwise if the user is authenticated we should - // check the remote system to get the users permissiosn. - default: - log.Debugf("Fetching team permission for %s %s", - user.Login, team) - - var err error - perm, err = cache.GetTeamPerms(c, user, team) - if err != nil { - // debug - log.Errorf("Error fetching team permission for %s %s", - user.Login, team) - - perm.Admin = false - perm.Pull = false - perm.Push = false - } - } - - if user != nil { - log.Debugf("%s granted %+v team permission to %s", - user.Login, perm, team) - } else { - log.Debugf("Guest granted %+v to %s", perm, team) - - perm.Admin = false - perm.Pull = false - perm.Push = false - } - - return perm -} - -func MustTeamAdmin() gin.HandlerFunc { - return func(c *gin.Context) { - perm := TeamPerm(c) - - if perm.Admin { - c.Next() - } else { - c.String(401, "User not authorized") - c.Abort() - } - } -} diff --git a/router/middleware/session/team_test.go b/router/middleware/session/team_test.go deleted file mode 100644 index a212a520a..000000000 --- a/router/middleware/session/team_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package session - -import ( - "testing" - - "github.com/drone/drone/cache" - "github.com/drone/drone/model" - "github.com/franela/goblin" - "github.com/gin-gonic/gin" -) - -func TestTeamPerm(t *testing.T) { - g := goblin.Goblin(t) - - g.Describe("TeamPerm", func() { - - var c *gin.Context - g.BeforeEach(func() { - c = new(gin.Context) - cache.ToContext(c, cache.Default()) - }) - - g.It("Should set admin to false (user not logged in)", func() { - p := TeamPerm(c) - g.Assert(p.Admin).IsFalse("admin should be false") - }) - g.It("Should set admin to true (user is DRONE_ADMIN)", func() { - // Set DRONE_ADMIN user - c.Set("user", fakeUserAdmin) - - p := TeamPerm(c) - g.Assert(p.Admin).IsTrue("admin should be false") - }) - g.It("Should set admin to false (user logged in, not owner of org)", func() { - // Set fake org - params := gin.Params{ - gin.Param{ - Key: "team", - Value: "test_org", - }, - } - c.Params = params - - // Set cache to show user does not Owner/Admin - cache.Set(c, "perms:octocat:test_org", fakeTeamPerm) - - // Set User - c.Set("user", fakeUser) - - p := TeamPerm(c) - g.Assert(p.Admin).IsFalse("admin should be false") - }) - g.It("Should set admin to true (user logged in, owner of org)", func() { - // Set fake org - params := gin.Params{ - gin.Param{ - Key: "team", - Value: "test_org", - }, - } - c.Params = params - - // Set cache to show user is Owner/Admin - cache.Set(c, "perms:octocat:test_org", fakeTeamPermAdmin) - - // Set User - c.Set("user", fakeUser) - - p := TeamPerm(c) - g.Assert(p.Admin).IsTrue("admin should be true") - }) - }) -} - -var ( - fakeUserAdmin = &model.User{ - Login: "octocatAdmin", - Token: "cfcd2084", - Admin: true, - } - - fakeUser = &model.User{ - Login: "octocat", - Token: "cfcd2084", - Admin: false, - } - - fakeTeamPermAdmin = &model.Perm{ - Admin: true, - } - - fakeTeamPerm = &model.Perm{ - Admin: false, - } -) diff --git a/router/router.go b/router/router.go index 897ffb1a4..456348f8e 100644 --- a/router/router.go +++ b/router/router.go @@ -47,7 +47,6 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { user.GET("", server.GetSelf) user.GET("/feed", server.GetFeed) user.GET("/repos", server.GetRepos) - user.GET("/repos/remote", server.GetRemoteRepos) user.POST("/token", server.PostToken) user.DELETE("/token", server.DeleteToken) } @@ -62,46 +61,42 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { users.DELETE("/:login", server.DeleteUser) } - repos := e.Group("/api/repos/:owner/:name") + repo := e.Group("/api/repos/:owner/:name") { - repos.POST("", server.PostRepo) + repo.Use(session.SetRepo()) + repo.Use(session.SetPerm()) + repo.Use(session.MustPull) - repo := repos.Group("") - { - repo.Use(session.SetRepo()) - repo.Use(session.SetPerm()) - repo.Use(session.MustPull) + repo.POST("", session.MustRepoAdmin(), server.PostRepo) + repo.GET("", server.GetRepo) + repo.GET("/builds", server.GetBuilds) + repo.GET("/builds/:number", server.GetBuild) + repo.GET("/logs/:number/:ppid/:proc", server.GetBuildLogs) - repo.GET("", server.GetRepo) - repo.GET("/builds", server.GetBuilds) - repo.GET("/builds/:number", server.GetBuild) - repo.GET("/logs/:number/:ppid/:proc", server.GetBuildLogs) + // requires push permissions + repo.GET("/secrets", session.MustPush, server.GetSecretList) + repo.POST("/secrets", session.MustPush, server.PostSecret) + repo.GET("/secrets/:secret", session.MustPush, server.GetSecret) + repo.PATCH("/secrets/:secret", session.MustPush, server.PatchSecret) + repo.DELETE("/secrets/:secret", session.MustPush, server.DeleteSecret) - // requires push permissions - repo.GET("/secrets", session.MustPush, server.GetSecretList) - repo.POST("/secrets", session.MustPush, server.PostSecret) - repo.GET("/secrets/:secret", session.MustPush, server.GetSecret) - repo.PATCH("/secrets/:secret", session.MustPush, server.PatchSecret) - repo.DELETE("/secrets/:secret", session.MustPush, server.DeleteSecret) + // requires push permissions + repo.GET("/registry", session.MustPush, server.GetRegistryList) + repo.POST("/registry", session.MustPush, server.PostRegistry) + repo.GET("/registry/:registry", session.MustPush, server.GetRegistry) + repo.PATCH("/registry/:registry", session.MustPush, server.PatchRegistry) + repo.DELETE("/registry/:registry", session.MustPush, server.DeleteRegistry) - // requires push permissions - repo.GET("/registry", session.MustPush, server.GetRegistryList) - repo.POST("/registry", session.MustPush, server.PostRegistry) - repo.GET("/registry/:registry", session.MustPush, server.GetRegistry) - repo.PATCH("/registry/:registry", session.MustPush, server.PatchRegistry) - repo.DELETE("/registry/:registry", session.MustPush, server.DeleteRegistry) + // requires admin permissions + repo.PATCH("", session.MustRepoAdmin(), server.PatchRepo) + repo.DELETE("", session.MustRepoAdmin(), server.DeleteRepo) + repo.POST("/chown", session.MustRepoAdmin(), server.ChownRepo) + repo.POST("/repair", session.MustRepoAdmin(), server.RepairRepo) - // requires push permissions - repo.PATCH("", session.MustPush, server.PatchRepo) - repo.DELETE("", session.MustRepoAdmin(), server.DeleteRepo) - repo.POST("/chown", session.MustRepoAdmin(), server.ChownRepo) - repo.POST("/repair", session.MustRepoAdmin(), server.RepairRepo) - - repo.POST("/builds/:number", session.MustPush, server.PostBuild) - repo.POST("/builds/:number/approve", session.MustPush, server.PostApproval) - repo.POST("/builds/:number/decline", session.MustPush, server.PostDecline) - repo.DELETE("/builds/:number/:job", session.MustPush, server.DeleteBuild) - } + repo.POST("/builds/:number", session.MustPush, server.PostBuild) + repo.POST("/builds/:number/approve", session.MustPush, server.PostApproval) + repo.POST("/builds/:number/decline", session.MustPush, server.PostDecline) + repo.DELETE("/builds/:number/:job", session.MustPush, server.DeleteBuild) } badges := e.Group("/api/badges/:owner/:name") diff --git a/server/hook.go b/server/hook.go index c427d176d..cdacbfc8e 100644 --- a/server/hook.go +++ b/server/hook.go @@ -84,6 +84,11 @@ func PostHook(c *gin.Context) { c.AbortWithError(404, err) return } + if !repo.IsActive { + logrus.Errorf("ignoring hook. %s/%s is inactive.", tmprepo.Owner, tmprepo.Name) + c.AbortWithError(204, err) + return + } // get the token and verify the hook is authorized parsed, err := token.ParseRequest(c.Request, func(t *token.Token) (string, error) { diff --git a/server/repo.go b/server/repo.go index 39b8a6205..6f9966bfd 100644 --- a/server/repo.go +++ b/server/repo.go @@ -4,11 +4,11 @@ import ( "encoding/base32" "fmt" "net/http" + "strconv" "github.com/gin-gonic/gin" "github.com/gorilla/securecookie" - "github.com/drone/drone/cache" "github.com/drone/drone/model" "github.com/drone/drone/remote" "github.com/drone/drone/router/middleware/session" @@ -20,54 +20,40 @@ import ( func PostRepo(c *gin.Context) { remote := remote.FromContext(c) user := session.User(c) - owner := c.Param("owner") - name := c.Param("name") + repo := session.Repo(c) - if user == nil { - c.AbortWithStatus(403) + if repo.IsActive { + c.String(409, "Repository is already active.") return } - r, err := remote.Repo(user, owner, name) - if err != nil { - c.String(404, err.Error()) - return + repo.IsActive = true + repo.UserID = user.ID + if !repo.AllowPush && !repo.AllowPull && !repo.AllowDeploy && !repo.AllowTag { + repo.AllowPush = true + repo.AllowPull = true } - m, err := cache.GetPerms(c, user, owner, name) - if err != nil { - c.String(404, err.Error()) - return + if repo.Visibility == "" { + repo.Visibility = model.VisibilityPublic + if repo.IsPrivate { + repo.Visibility = model.VisibilityPrivate + } } - if !m.Admin { - c.String(403, "Administrative access is required.") - return + if repo.Config == "" { + repo.Config = ".drone.yml" + } + if repo.Timeout == 0 { + repo.Timeout = 60 // 1 hour default build time + } + if repo.Hash == "" { + repo.Hash = base32.StdEncoding.EncodeToString( + securecookie.GenerateRandomKey(32), + ) } - // error if the repository already exists - _, err = store.GetRepoOwnerName(c, owner, name) - if err == nil { - c.String(409, "Repository already exists.") - return - } - - // set the repository owner to the - // currently authenticated user. - r.UserID = user.ID - r.AllowPush = true - r.AllowPull = true - r.Visibility = model.VisibilityPublic - r.Config = ".drone.yml" - r.Timeout = 60 // 1 hour default build time - r.Hash = base32.StdEncoding.EncodeToString( - securecookie.GenerateRandomKey(32), - ) - if r.IsPrivate { - r.Visibility = model.VisibilityPrivate - } - - // crates the jwt token used to verify the repository - t := token.New(token.HookToken, r.FullName) - sig, err := t.Sign(r.Hash) + // creates the jwt token used to verify the repository + t := token.New(token.HookToken, repo.FullName) + sig, err := t.Sign(repo.Hash) if err != nil { c.String(500, err.Error()) return @@ -79,22 +65,19 @@ func PostRepo(c *gin.Context) { sig, ) - // activate the repository before we make any - // local changes to the database. - err = remote.Activate(user, r, link) + err = remote.Activate(user, repo, link) if err != nil { c.String(500, err.Error()) return } - // persist the repository - err = store.CreateRepo(c, r) + err = store.UpdateRepo(c, repo) if err != nil { c.String(500, err.Error()) return } - c.JSON(200, r) + c.JSON(200, repo) } func PatchRepo(c *gin.Context) { @@ -173,16 +156,28 @@ func GetRepo(c *gin.Context) { } func DeleteRepo(c *gin.Context) { + remove, _ := strconv.ParseBool(c.Query("remove")) remote := remote.FromContext(c) repo := session.Repo(c) user := session.User(c) - err := store.DeleteRepo(c, repo) + repo.IsActive = false + repo.UserID = 0 + + err := store.UpdateRepo(c, repo) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } + if remove { + err := store.DeleteRepo(c, repo) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } + } + remote.Deactivate(user, repo, httputil.GetURL(c.Request)) c.Writer.WriteHeader(http.StatusOK) } diff --git a/server/stream.go b/server/stream.go index 2412453ed..db896a0da 100644 --- a/server/stream.go +++ b/server/stream.go @@ -9,7 +9,6 @@ import ( "github.com/cncd/logging" "github.com/cncd/pubsub" - "github.com/drone/drone/cache" "github.com/drone/drone/model" "github.com/drone/drone/router/middleware/session" "github.com/drone/drone/store" @@ -149,7 +148,10 @@ func EventStream(c *gin.Context) { user := session.User(c) repo := map[string]bool{} if user != nil { - repo, _ = cache.GetRepoMap(c, user) + repos, _ := store.FromContext(c).RepoList(user) + for _, r := range repos { + repo[r.FullName] = true + } } ticker := time.NewTicker(pingPeriod) diff --git a/server/sync.go b/server/sync.go new file mode 100644 index 000000000..adac83a7a --- /dev/null +++ b/server/sync.go @@ -0,0 +1,66 @@ +package server + +import ( + "time" + + "github.com/drone/drone/model" + "github.com/drone/drone/remote" + "github.com/drone/drone/store" +) + +// Syncer synces the user repository and permissions. +type Syncer interface { + Sync(user *model.User) error +} + +type syncer struct { + remote remote.Remote + store store.Store + perms model.PermStore +} + +func (s *syncer) Sync(user *model.User) error { + unix := time.Now().Unix() - 1 // force immediate expiration + repos, err := s.remote.Repos(user) + if err != nil { + return err + } + + var perms []*model.Perm + for _, repo := range repos { + perm := model.Perm{ + UserID: user.ID, + Repo: repo.FullName, + Pull: true, + Synced: unix, + } + if repo.Perm != nil { + perm.Push = repo.Perm.Push + perm.Admin = repo.Perm.Admin + } + perms = append(perms, &perm) + } + + err = s.store.RepoBatch(repos) + if err != nil { + return err + } + + err = s.store.PermBatch(perms) + if err != nil { + return err + } + + // this is here as a precaution. I want to make sure that if an api + // call to the version control system fails and (for some reason) returns + // an empty list, we don't wipe out the user repository permissions. + // + // the side-effect of this code is that a user with 1 repository whose + // access is removed will still display in the feed, but they will not + // be able to access the actual repository data. + if len(repos) == 0 { + return nil + } + + return s.perms.PermFlush(user, unix) +} diff --git a/server/template/files/index_polymer.html b/server/template/files/index_polymer.html index ce1fc9fe9..05d4e6489 100644 --- a/server/template/files/index_polymer.html +++ b/server/template/files/index_polymer.html @@ -5,6 +5,9 @@ + + +