Add Config test
This commit is contained in:
parent
5ac9e23f3f
commit
181c163669
|
@ -3,8 +3,9 @@ package main
|
|||
const DefaultAuthorEmail = "stick@notes.app"
|
||||
|
||||
type Author struct {
|
||||
Key string
|
||||
Username string
|
||||
Name string
|
||||
Key string
|
||||
Name string
|
||||
Email string
|
||||
|
||||
Notebooks []*Notebook
|
||||
}
|
||||
|
|
119
config.go
119
config.go
|
@ -1,36 +1,75 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthorAccessRead = 0
|
||||
AuthorAccessCheck = 1
|
||||
AuthorAccessWrite = 2
|
||||
)
|
||||
|
||||
const DefaultConfigPath = "~/.config/stick/stick.yml"
|
||||
|
||||
type Config struct {
|
||||
Salt string
|
||||
Serve string
|
||||
|
||||
Authors []*AuthorConfig
|
||||
Notebooks []*NotebookConfig
|
||||
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func (c *Config) load(path string) {
|
||||
var err error
|
||||
type AuthorConfig struct {
|
||||
Email string
|
||||
Name string
|
||||
}
|
||||
|
||||
type NotebookConfig struct {
|
||||
Label string
|
||||
Repo string
|
||||
Serve map[string]int
|
||||
}
|
||||
|
||||
func ReadConfigFile(path string) (*Config, error) {
|
||||
var err error
|
||||
if path == "" {
|
||||
path = DefaultConfigPath
|
||||
}
|
||||
path, err = expandPath(path)
|
||||
CheckError(err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(path)
|
||||
CheckError(err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Config{}
|
||||
err = c.load(data)
|
||||
return c, err
|
||||
}
|
||||
|
||||
func ReadConfigData(data []byte) (*Config, error) {
|
||||
c := &Config{}
|
||||
err := c.load(data)
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (c *Config) load(data []byte) error {
|
||||
var config map[string]interface{}
|
||||
err = yaml.Unmarshal(data, &config)
|
||||
CheckError(err)
|
||||
err := yaml.Unmarshal(data, &config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if salt, ok := config["salt"]; ok {
|
||||
c.Salt = salt.(string)
|
||||
|
@ -40,16 +79,13 @@ func (c *Config) load(path string) {
|
|||
c.Serve = serve.(string)
|
||||
}
|
||||
|
||||
stick.Authors = map[string]*Author{}
|
||||
if as, ok := config["authors"]; ok {
|
||||
auths := as.(map[interface{}]interface{})
|
||||
|
||||
for author, name := range auths {
|
||||
stick.Authors[hash(author.(string))] = &Author{Key: hash(author.(string)), Username: author.(string), Name: name.(string)}
|
||||
for aemail, aname := range auths {
|
||||
c.Authors = append(c.Authors, &AuthorConfig{Email: aemail.(string), Name: aname.(string)})
|
||||
}
|
||||
}
|
||||
|
||||
stick.Notebooks = map[string]*Notebook{}
|
||||
if nbsv, ok := config["notebooks"]; ok {
|
||||
nbs := nbsv.(map[interface{}]interface{})
|
||||
var labels []string
|
||||
|
@ -57,51 +93,52 @@ func (c *Config) load(path string) {
|
|||
labels = append(labels, label.(string))
|
||||
}
|
||||
sort.Strings(labels)
|
||||
|
||||
for _, label := range labels {
|
||||
notebookrepo := ""
|
||||
var notebookserve []string
|
||||
nbconfig := &NotebookConfig{Label: label, Serve: make(map[string]int)}
|
||||
|
||||
nbo := nbs[label].(map[interface{}]interface{})
|
||||
for option, v := range nbo {
|
||||
switch option.(string) {
|
||||
case "repo":
|
||||
notebookrepo = v.(string)
|
||||
break
|
||||
nbconfig.Repo = v.(string)
|
||||
case "serve":
|
||||
nbsv := v.([]interface{})
|
||||
for _, nbserve := range nbsv {
|
||||
notebookserve = append(notebookserve, hash(nbserve.(string)))
|
||||
for _, nbsvi := range nbsv {
|
||||
switch nbsvi.(type) {
|
||||
case string:
|
||||
nbconfig.Serve[nbsvi.(string)] = AuthorAccessWrite
|
||||
case map[interface{}]interface{}:
|
||||
nbsvx := nbsvi.(map[interface{}]interface{})
|
||||
for nbsvxi, nbsvxa := range nbsvx {
|
||||
access := -1
|
||||
switch nbsvxa.(string) {
|
||||
case "read":
|
||||
access = AuthorAccessRead
|
||||
case "check":
|
||||
access = AuthorAccessCheck
|
||||
case "write":
|
||||
access = AuthorAccessWrite
|
||||
}
|
||||
if access == -1 {
|
||||
return errors.New(fmt.Sprintf("invalid serve configuration: invalid access level specified for %s (%s should be read/check/write)", nbsvxi, nbsvxa.(string)))
|
||||
}
|
||||
|
||||
nbconfig.Serve[nbsvxi.(string)] = access
|
||||
}
|
||||
default:
|
||||
return errors.New(fmt.Sprintf("invalid serve configuration: %T", nbsvi))
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if notebookrepo == "" {
|
||||
panic("invalid notebook configuration: no repo path supplied")
|
||||
if nbconfig.Repo == "" {
|
||||
return errors.New("invalid notebook configuration: no repo path supplied")
|
||||
}
|
||||
|
||||
notebook, err := LoadNotebook(notebookrepo)
|
||||
CheckError(err)
|
||||
|
||||
notebook.ID = hash(label)
|
||||
notebook.Label = label
|
||||
notebook.Serve = notebookserve
|
||||
sort.Strings(notebook.Serve)
|
||||
|
||||
stick.Notebooks[hash(label)] = notebook
|
||||
c.Notebooks = append(c.Notebooks, nbconfig)
|
||||
}
|
||||
}
|
||||
|
||||
var author *Author
|
||||
for _, notebook := range stick.Notebooks {
|
||||
for _, serveauth := range notebook.Serve {
|
||||
author = stick.getAuthor(serveauth)
|
||||
if author == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
author.Notebooks = append(author.Notebooks, notebook)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var configData = []byte(`
|
||||
salt: 'xXxN4CLxXx'
|
||||
|
||||
authors:
|
||||
read@stick.rocketnine.space: 'Read Access'
|
||||
check@stick.rocketnine.space: 'Check Access'
|
||||
write@stick.rocketnine.space: 'Write Access'
|
||||
|
||||
notebooks:
|
||||
Test Notebook A:
|
||||
repo: /home/stick/repo/a
|
||||
serve:
|
||||
- read@stick.rocketnine.space: read
|
||||
- write@stick.rocketnine.space: write
|
||||
Test Notebook B:
|
||||
repo: /home/stick/repo/b
|
||||
serve:
|
||||
- check@stick.rocketnine.space: check
|
||||
- write@stick.rocketnine.space
|
||||
`)
|
||||
|
||||
c, err := ReadConfigData(configData)
|
||||
if err != nil {
|
||||
t.Errorf("failed to load config data: %+v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, false, c.Debug)
|
||||
assert.Equal(t, "xXxN4CLxXx", c.Salt)
|
||||
assert.Equal(t, []*AuthorConfig{
|
||||
{Email: "read@stick.rocketnine.space", Name: "Read Access"},
|
||||
{Email: "check@stick.rocketnine.space", Name: "Check Access"},
|
||||
{Email: "write@stick.rocketnine.space", Name: "Write Access"}},
|
||||
c.Authors)
|
||||
assert.Equal(t, []*NotebookConfig{
|
||||
{Label: "Test Notebook A", Repo: "/home/stick/repo/a", Serve: map[string]int{"read@stick.rocketnine.space": AuthorAccessRead, "write@stick.rocketnine.space": AuthorAccessWrite}},
|
||||
{Label: "Test Notebook B", Repo: "/home/stick/repo/b", Serve: map[string]int{"check@stick.rocketnine.space": AuthorAccessCheck, "write@stick.rocketnine.space": AuthorAccessWrite}}},
|
||||
c.Notebooks)
|
||||
}
|
|
@ -41,7 +41,7 @@ const DefaultSubmoduleDepth = 10
|
|||
type Notebook struct {
|
||||
ID string
|
||||
Label string
|
||||
Serve []string `json:"-"`
|
||||
Serve map[string]int `json:"-"`
|
||||
|
||||
Repository *git.Repository `json:"-"`
|
||||
}
|
||||
|
|
57
stick.go
57
stick.go
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Stick struct {
|
||||
Config *Config
|
||||
|
@ -13,10 +15,59 @@ type Stick struct {
|
|||
}
|
||||
|
||||
func Initialize(configPath string, debug bool) {
|
||||
var err error
|
||||
|
||||
stick = &Stick{}
|
||||
stick.Config = &Config{}
|
||||
stick.Config.load(configPath)
|
||||
stick.Config, err = ReadConfigFile(configPath)
|
||||
CheckError(err)
|
||||
|
||||
stick.Config.Debug = debug
|
||||
StickSalt = []byte(stick.Config.Salt)
|
||||
|
||||
stick.loadAuthors()
|
||||
stick.loadNotebooks()
|
||||
}
|
||||
|
||||
func (s *Stick) loadAuthors() {
|
||||
// TODO: Allow reloading config
|
||||
|
||||
stick.Authors = map[string]*Author{}
|
||||
for _, author := range stick.Config.Authors {
|
||||
stick.Authors[hash(author.Email)] = &Author{Key: hash(author.Email), Email: author.Email, Name: author.Name}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Stick) loadNotebooks() {
|
||||
// TODO: Allow reloading config
|
||||
|
||||
stick.Notebooks = make(map[string]*Notebook)
|
||||
for _, nbconfig := range stick.Config.Notebooks {
|
||||
notebook, err := LoadNotebook(nbconfig.Repo)
|
||||
CheckError(err)
|
||||
|
||||
notebook.ID = hash(nbconfig.Label)
|
||||
notebook.Label = nbconfig.Label
|
||||
|
||||
notebook.Serve = make(map[string]int)
|
||||
for serveauthor, serveaccess := range nbconfig.Serve {
|
||||
notebook.Serve[hash(serveauthor)] = serveaccess
|
||||
}
|
||||
|
||||
stick.Notebooks[hash(nbconfig.Label)] = notebook
|
||||
}
|
||||
|
||||
var author *Author
|
||||
for _, notebook := range stick.Notebooks {
|
||||
for serveauth := range notebook.Serve {
|
||||
author = stick.getAuthor(serveauth)
|
||||
if author == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
author.Notebooks = append(author.Notebooks, notebook)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *Stick) getAuthor(key string) *Author {
|
||||
|
|
10
utils.go
10
utils.go
|
@ -10,6 +10,8 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var StickSalt []byte
|
||||
|
||||
func expandPath(path string) (string, error) {
|
||||
if !strings.HasPrefix(path, "~") {
|
||||
return path, nil
|
||||
|
@ -23,12 +25,16 @@ func expandPath(path string) (string, error) {
|
|||
return homedir + path[1:], nil
|
||||
}
|
||||
|
||||
func hash(str string) string {
|
||||
h := hmac.New(sha256.New, []byte(stick.Config.Salt))
|
||||
func hashWithSalt(str string, salt []byte) string {
|
||||
h := hmac.New(sha256.New, salt)
|
||||
h.Write([]byte(str))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func hash(str string) string {
|
||||
return hashWithSalt(str, StickSalt)
|
||||
}
|
||||
|
||||
func elapsed(what string) func() {
|
||||
start := time.Now()
|
||||
return func() {
|
||||
|
|
2
web.go
2
web.go
|
@ -196,7 +196,7 @@ func printServedNotebooks() {
|
|||
}
|
||||
|
||||
log.Println()
|
||||
log.Printf("%-10s http://%s/#%s", author.Name[0:int(math.Min(10, float64(len(author.Name))))], stick.Config.Serve, authkey)
|
||||
log.Printf("%-10s http://%s/#login/%s", author.Name[0:int(math.Min(10, float64(len(author.Name))))], stick.Config.Serve, authkey)
|
||||
for _, notebook := range author.Notebooks {
|
||||
log.Printf("- %s", notebook.Label[0:int(math.Min(20, float64(len(notebook.Label))))])
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue