tokens, last build

This commit is contained in:
Brad Rydzewski 2015-04-10 22:22:55 -07:00
parent 840ea6d595
commit 087f92f41f
13 changed files with 127 additions and 58 deletions

View file

@ -20,7 +20,7 @@ type Repo struct {
Created int64 `json:"created_at"`
Updated int64 `json:"updated_at"`
User *User `json:"user,omitempty"`
User *Owner `json:"user,omitempty"`
Last *Build `json:"last_build,omitempty"`
}
@ -32,6 +32,11 @@ type Keypair struct {
Private string `json:"-"`
}
// Owner represents the owner of a repository.
type Owner struct {
Login string `json:"login"`
}
// Subscriber represents a user's subscription
// to a repository. This determines if the repository
// is displayed on the user dashboard and in the user

View file

@ -14,4 +14,8 @@ type User struct {
// Repos contains a list of subscriptions
// to repositories the user is watching.
Repos map[string]struct{} `json:"-"`
// Tokens contains a list of tokens for
// the user account.
Tokens map[string]struct{} `json:"-"`
}

View file

@ -35,9 +35,15 @@ func (db *DB) GetBuildList(repo string) ([]*common.Build, error) {
// GetBuildLast gets the last executed build for the
// named repository.
func (db *DB) GetBuildLast(repo string) (*common.Build, error) {
// get the last build sequence number (stored in key in `bucketBuildSeq`)
// return that build
return nil, nil
key := []byte(repo)
build := &common.Build{}
err := db.View(func(t *bolt.Tx) error {
raw := t.Bucket(bucketBuildSeq).Get(key)
num := binary.LittleEndian.Uint32(raw)
key = []byte(repo + "/" + strconv.FormatUint(uint64(num), 10))
return get(t, bucketBuild, key, build)
})
return build, err
}
// GetBuildStatus gets the named build status for the
@ -78,17 +84,17 @@ func (db *DB) GetBuildStatusList(repo string, build int) ([]*common.Status, erro
func (db *DB) InsertBuild(repo string, build *common.Build) error {
key := []byte(repo)
return db.Update(func (t *bolt.Tx) error {
return db.Update(func(t *bolt.Tx) error {
raw, err := raw(t, bucketBuildSeq, key)
var next_seq uint32
switch err {
case ErrKeyNotFound:
next_seq = 1
case nil:
next_seq = 1 + binary.LittleEndian.Uint32(raw)
default:
return err
case ErrKeyNotFound:
next_seq = 1
case nil:
next_seq = 1 + binary.LittleEndian.Uint32(raw)
default:
return err
}
// covert our seqno to raw value

View file

@ -42,5 +42,15 @@ func TestBuild(t *testing.T) {
g.Assert(build.State).Equal("success")
})
g.It("Should get the latest builds", func() {
db.InsertBuild(repo, &common.Build{State: "success"})
db.InsertBuild(repo, &common.Build{State: "success"})
db.InsertBuild(repo, &common.Build{State: "pending"})
build, err := db.GetBuildLast(repo)
g.Assert(err).Equal(nil)
g.Assert(build.State).Equal("pending")
g.Assert(build.Number).Equal(3)
})
})
}

View file

@ -73,7 +73,13 @@ func TestUser(t *testing.T) {
g.Assert(err).Equal(ErrKeyNotFound)
})
g.It("Should list")
g.It("Should list", func() {
db.InsertUser(&common.User{Login: "bert"})
db.InsertUser(&common.User{Login: "ernie"})
users, err := db.GetUserList()
g.Assert(err).Equal(nil)
g.Assert(len(users)).Equal(2)
})
g.It("Should count", func() {
db.InsertUser(&common.User{Login: "bert"})

View file

@ -1,8 +1,8 @@
package bolt
import (
"github.com/youtube/vitess/go/bson"
"github.com/boltdb/bolt"
"github.com/youtube/vitess/go/bson"
)
func encode(v interface{}) ([]byte, error) {
@ -35,11 +35,7 @@ func update(t *bolt.Tx, bucket, key []byte, v interface{}) error {
t.Rollback()
return err
}
err = t.Bucket(bucket).Put(key, raw)
if err != nil {
return err
}
return nil
return t.Bucket(bucket).Put(key, raw)
}
func insert(t *bolt.Tx, bucket, key []byte, v interface{}) error {
@ -53,17 +49,9 @@ func insert(t *bolt.Tx, bucket, key []byte, v interface{}) error {
if t.Bucket(bucket).Get(key) != nil {
return ErrKeyExists
}
err = t.Bucket(bucket).Put(key, raw)
if err != nil {
return err
}
return nil
return t.Bucket(bucket).Put(key, raw)
}
func delete(t *bolt.Tx, bucket, key []byte) error {
err := t.Bucket(bucket).Delete(key)
if err != nil {
return err
}
return nil
return t.Bucket(bucket).Delete(key)
}

View file

@ -114,7 +114,7 @@ func main() {
logs.Use(server.CheckPull())
logs.Use(server.CheckPush())
logs.GET("", server.GetLogs)
logs.GET("", server.GetTaskLogs)
}
status := api.Group("/status/:owner/:name/:number")

View file

@ -166,7 +166,7 @@ func getLoginBasic(c *gin.Context) {
var (
remote = ToRemote(c)
username = c.Request.FormValue("username")
password = c.Request.FormValue("username")
password = c.Request.FormValue("password")
)
// get user account

View file

@ -1,27 +0,0 @@
package server
import (
"strconv"
"github.com/gin-gonic/gin"
)
// GetLogs accepts a request to retrieve logs from the
// datastore for the given repository, build and task
// number.
//
// GET /api/logs/:owner/:name/:number/:task
//
func GetLogs(c *gin.Context) {
ds := ToDatastore(c)
repo := ToRepo(c)
build, _ := strconv.Atoi(c.Params.ByName("number"))
task, _ := strconv.Atoi(c.Params.ByName("task"))
logs, err := ds.GetTaskLogs(repo.FullName, build, task)
if err != nil {
c.Fail(404, err)
} else {
c.Writer.Write(logs)
}
}

View file

@ -193,7 +193,7 @@ func PostRepo(c *gin.Context) {
// set the repository owner to the
// currently authenticated user.
r.User = user
r.User = &common.Owner{Login: user.Login}
// generate an RSA key and add to the repo
key, err := sshutil.GeneratePrivateKey()

View file

@ -44,3 +44,23 @@ func GetTasks(c *gin.Context) {
c.JSON(200, tasks)
}
}
// GetTaskLogs accepts a request to retrieve logs from the
// datastore for the given repository, build and task
// number.
//
// GET /api/logs/:owner/:name/:number/:task
//
func GetTaskLogs(c *gin.Context) {
ds := ToDatastore(c)
repo := ToRepo(c)
build, _ := strconv.Atoi(c.Params.ByName("number"))
task, _ := strconv.Atoi(c.Params.ByName("task"))
logs, err := ds.GetTaskLogs(repo.FullName, build, task)
if err != nil {
c.Fail(404, err)
} else {
c.Writer.Write(logs)
}
}

40
server/token.go Normal file
View file

@ -0,0 +1,40 @@
package server
import (
"github.com/gin-gonic/gin"
// "github.com/drone/drone/common"
)
// POST /api/user/tokens
func PostToken(c *gin.Context) {
// 1. generate a unique, random password
// 2. take a hash of the password, and store in the database
// 3. return the random password to the UI and instruct the user to copy it
}
// DELETE /api/user/tokens/:sha
func DelToken(c *gin.Context) {
store := ToDatastore(c)
user := ToUser(c)
hash := c.Params.ByName("hash")
token, err := store.GetToken(hash)
if err != nil {
c.Fail(404, err)
}
err = store.DeleteToken(token)
if err != nil {
c.Fail(400, err)
}
// TODO(bradrydzewski) this should be encapsulated
// in our database code, since this feels like a
// database-specific implementation.
delete(user.Tokens, token.Sha)
err = store.UpdateUser(user)
if err != nil {
c.Fail(400, err)
} else {
c.Writer.WriteHeader(200)
}
}

View file

@ -57,3 +57,20 @@ func GetUserRepos(c *gin.Context) {
c.JSON(200, &repos)
}
}
// GetUserTokens accepts a request to get the currently
// authenticated user's token list from the datastore,
// encoded and returned in JSON format.
//
// GET /api/user/tokens
//
func GetUserTokens(c *gin.Context) {
// ds := ToDatastore(c)
// me := ToUser(c)
// tokens, err := ds.GetUserTokens(me.Login)
// if err != nil {
// c.Fail(400, err)
// } else {
// c.JSON(200, &repos)
// }
}