diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cdf8e76
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,48 @@
+.DEFAULT_GOAL := help
+SHELL := bash
+.ONESHELL:
+.SHELLFLAGS := -eu -o pipefail -c
+.DELETE_ON_ERROR:
+MAKEFLAGS += --warn-undefined-variables
+MAKEFLAGS += --no-builtin-rules
+
+ifeq ($(origin .RECIPEPREFIX), undefined)
+ $(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
+endif
+.RECIPEPREFIX = >
+
+# Default - top level rule is what gets ran when you run just `make`
+build: out/image-id
+.PHONY: build
+
+# Clean up the output directories; since all the sentinel files go under tmp, this will cause everything to get rebuilt
+clean:
+> rm -rf tmp
+> rm -rf out
+.PHONY: clean
+
+# Tests - re-ran if any file under src has been changed since tmp/.tests-passed.sentinel was last touched
+tmp/.tests-passed.sentinel: $(shell find src -type f)
+> mkdir -p $(@D)
+> node run test
+> touch $@
+
+# Webpack - re-built if the tests have been rebuilt (and so, by proxy, whenever the source files have changed)
+tmp/.packed.sentinel: tmp/.tests-passed.sentinel
+> mkdir -p $(@D)
+> webpack ..
+> touch $@
+
+# Docker image - re-built if the webpack output has been rebuilt
+out/image-id: tmp/.packed.sentinel
+> mkdir -p $(@D)
+> image_id="example.com/my-app:$$(pwgen -1)"
+> docker build --tag="$${image_id}
+> echo "$${image_id}" > out/image-id
+
+help:
+
+ # @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
+ # | sed -n 's/^\(.*\): \(.*\)##\(.*\)/\1\3/p' \
+ # | column -t -s ' '
+.PHONY: help
diff --git a/cmd/auth-demo/home.html b/cmd/auth-demo/home.html
deleted file mode 100755
index 220ec05..0000000
--- a/cmd/auth-demo/home.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cmd/auth-demo/main.go b/cmd/auth-demo/main.go
deleted file mode 100755
index de835bb..0000000
--- a/cmd/auth-demo/main.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package main
-
-import (
- "net/http"
- "os"
-
- "github.com/codegangsta/negroni"
- "github.com/jchenry/jchenry/internal/auth"
- _http "github.com/jchenry/jchenry/internal/http"
-)
-
-func main() {
- auth.Init()
- StartServer()
-}
-
-func StartServer() {
- auth.PrintConfig()
- s := _http.NewServer(negroni.New(), _http.NewJulienschmidtHTTPRouter()).
- Static("/public/*filepath", http.Dir("public/")).
- Service("", auth.Service(auth.FromEnv())).
- Get("/", "", http.HandlerFunc(HomeHandler))
-
- port := os.Getenv("PORT")
- if port == "" {
- port = "3000"
- }
-
- s.Run(":" + port)
-}
-
-func HomeHandler(w http.ResponseWriter, r *http.Request) {
- _http.RenderTemplate(w, "home", nil)
-}
diff --git a/cmd/auth-demo/public/app.css b/cmd/auth-demo/public/app.css
deleted file mode 100755
index 5d6a003..0000000
--- a/cmd/auth-demo/public/app.css
+++ /dev/null
@@ -1,95 +0,0 @@
-body {
- font-family: "proxima-nova", sans-serif;
- text-align: center;
- font-size: 300%;
- font-weight: 100;
- }
- input[type=checkbox],
- input[type=radio] {
- position: absolute;
- opacity: 0;
- }
- input[type=checkbox] + label,
- input[type=radio] + label {
- display: inline-block;
- }
- input[type=checkbox] + label:before,
- input[type=radio] + label:before {
- content: "";
- display: inline-block;
- vertical-align: -0.2em;
- width: 1em;
- height: 1em;
- border: 0.15em solid #0074d9;
- border-radius: 0.2em;
- margin-right: 0.3em;
- background-color: white;
- }
- input[type=radio] + label:before {
- border-radius: 50%;
- }
- input[type=radio]:checked + label:before,
- input[type=checkbox]:checked + label:before {
- background-color: #0074d9;
- box-shadow: inset 0 0 0 0.15em white;
- }
- input[type=radio]:focus + label:before,
- input[type=checkbox]:focus + label:before {
- outline: 0;
- }
- .btn {
- font-size: 140%;
- text-transform: uppercase;
- letter-spacing: 1px;
- border: 0;
- background-color: #16214D;
- color: white;
- }
- .btn:hover {
- background-color: #44C7F4;
- }
- .btn:focus {
- outline: none !important;
- }
- .btn.btn-lg {
- padding: 20px 30px;
- }
- .btn:disabled {
- background-color: #333;
- color: #666;
- }
- h1,
- h2,
- h3 {
- font-weight: 100;
- }
- #logo img {
- width: 300px;
- margin-bottom: 60px;
- }
- .home-description {
- font-weight: 100;
- margin: 100px 0;
- }
- h2 {
- margin-top: 30px;
- margin-bottom: 40px;
- font-size: 200%;
- }
- label {
- font-size: 100%;
- font-weight: 300;
- }
- .btn-next {
- margin-top: 30px;
- }
- .answer {
- width: 70%;
- margin: auto;
- text-align: left;
- padding-left: 10%;
- margin-bottom: 20px;
- }
- .login-page .login-box {
- padding: 100px 0;
- }
\ No newline at end of file
diff --git a/cmd/auth-demo/run.sh b/cmd/auth-demo/run.sh
deleted file mode 100755
index f129eda..0000000
--- a/cmd/auth-demo/run.sh
+++ /dev/null
@@ -1 +0,0 @@
-AUTH_DOMAIN="https://dev-pb4s8m55.auth0.com/" AUTH_CLIENT_ID="ae1e02bTwXA35O3r3Xxk4kbRf31j5ge9" AUTH_CLIENT_SECRET="NFC5KYeM9GA2z0ptvzKPo9jmkQDRjx_WcsWyK0hzOJmr1CykS9cEmTcNh0-hKiMd" AUTH_CALLBACK_URL="http://localhost:3000/callback" ./auth-demo
\ No newline at end of file
diff --git a/cmd/auth-demo/user.html b/cmd/auth-demo/user.html
deleted file mode 100755
index e327ed3..0000000
--- a/cmd/auth-demo/user.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Welcome {{.Nickname}}
-
Logout
-
-
-
-
-
\ No newline at end of file
diff --git a/cmd/email-stats/main.go b/cmd/email-stats/main.go
deleted file mode 100755
index a4ea546..0000000
--- a/cmd/email-stats/main.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package main
-
-import (
- "fmt"
- "log"
- "sort"
-
- "github.com/rsc/rsc/google"
- "github.com/rsc/rsc/imap"
-)
-
-type Pair struct {
- Key string
- Value uint64
-}
-
-type PairList []*Pair
-
-func (p PairList) Len() int { return len(p) }
-func (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value }
-func (p PairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-
-func main() {
-
- acct := google.Acct("")
-
- c, err := imap.NewClient(imap.TLS, "imap.gmail.com", acct.Email, acct.Password, "/")
- if err != nil {
- log.Fatal(err)
- }
-
- all := c.Inbox()
- // all := c.Box("[Gmail]/All Mail")
-
- if err := all.Check(); err != nil {
- log.Fatal(err)
- }
-
- msgs := all.Msgs()
-
- counts := make(map[string]*Pair)
- labels := make(map[string]struct{})
- var pairs PairList = make([]*Pair, 0)
-
- for _, m := range msgs {
- ls := m.GmailLabels
- for _, l := range ls {
- labels[l] = struct{}{}
- }
-
- email := m.Hdr.From[0].Email
- if _, ok := counts[email]; ok {
- counts[email].Value = counts[email].Value + 1
- } else {
- p := Pair{email, 1}
- pairs = append(pairs, &p)
- counts[email] = &p
- }
- }
-
- keys := []string{}
-
- for k := range counts {
- keys = append(keys, k)
- }
-
- sort.Sort(pairs)
-
- for _, e := range pairs {
- fmt.Printf("%d %s\t\t\thttps://mail.google.com/mail/u/0/#search/in%%3Ainbox+from%%3A(%s)\n", e.Value, e.Key, e.Key)
- }
-
- // for k, _ := range labels {
- // fmt.Printf("%s, ", k)
- // }
- fmt.Println()
-
-}
diff --git a/cmd/gcal2calendar/main.go b/cmd/gcal2calendar/main.go
deleted file mode 100644
index d5ebdb7..0000000
--- a/cmd/gcal2calendar/main.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
- "time"
-
- "github.com/PuloV/ics-golang"
-)
-
-func main() {
-
- // calendarFile = flag.String("f", os.Env, "the calendar to convert")
- help := flag.Bool("help", false, "this help.")
- flag.Parse()
- if *help {
- flag.Usage()
- return
- }
-
- parser := ics.New()
- parserChan := parser.GetInputChan()
- outputChan := parser.GetOutputChan()
- go func() {
- nowYear := time.Now().Year()
- for event := range outputChan {
- if event.GetStart().Year() == nowYear {
- printEvent(event)
- }
- }
- }()
-
- parserChan <- "https://calendar.google.com/calendar/ical/colin%40jchenry.me/private-ff5ffa18eb856032d166c7f410fe33c0/basic.ics"
-
- parser.Wait()
-}
-
-func printEvent(evt *ics.Event) {
- fmt.Printf("%s - %s : %s (%s)\n", fmtTime(evt.GetStart()), fmtTime(evt.GetEnd()), evt.GetSummary(), evt.GetLocation())
-}
-
-func fmtTime(t time.Time) string {
- loc, err := time.LoadLocation("America/Los_Angeles")
- if err != nil {
- panic("bad timezone")
- }
-
- return t.In(loc).Format("Jan 02\t2006 15:04 MST")
-}
diff --git a/cmd/jchsh/main.go b/cmd/jchsh/main.go
deleted file mode 100644
index e08dae3..0000000
--- a/cmd/jchsh/main.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package main
-
-import (
- "bufio"
- "errors"
- "fmt"
- "os"
- "os/exec"
- "strings"
- "time"
-
- "github.com/jchenry/jchenry/pkg/arvelie"
- "github.com/jchenry/jchenry/pkg/neralie"
-)
-
-func main() {
- if err := run(); err != nil {
- fmt.Fprintf(os.Stderr, "%s\n", err)
- os.Exit(1)
- }
-}
-
-func run() (err error) {
- PS1 := "[%]: "
- reader := bufio.NewReader(os.Stdin)
-
- for {
- fmt.Print(PS1)
- if input, err := reader.ReadString('\n'); err == nil {
- if err = execute(input); err != nil {
- fmt.Fprintf(os.Stderr, err.Error())
- }
- } else {
- fmt.Fprintln(os.Stderr, err.Error())
- }
-
- }
-
-}
-
-func execute(input string) error {
- input = strings.TrimSuffix(input, "\n")
- args := strings.Split(input, " ")
-
- switch args[0] {
- case "cd":
- if len(args) < 2 {
- return errors.New("path required")
- }
- return os.Chdir(args[1])
- case "now":
- t := time.Now()
- fmt.Printf("%s %s\n", arvelie.FromDate(t), neralie.FromTime(t))
- return nil
- case "exit":
- os.Exit(0)
- }
-
- cmd := exec.Command(args[0], args[1:]...)
- cmd.Stdin = os.Stdin
- cmd.Stderr = os.Stderr
- cmd.Stdout = os.Stdout
- return cmd.Run()
-}
diff --git a/cmd/now/main.go b/cmd/now/main.go
deleted file mode 100755
index 9f3b79d..0000000
--- a/cmd/now/main.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package main
-
-import (
- "fmt"
- "time"
-
- "github.com/jchenry/jchenry/pkg/neralie"
-)
-
-func main() {
- a := neralie.FromTime(time.Now())
- fmt.Println(a)
-}
diff --git a/cmd/now/now b/cmd/now/now
deleted file mode 100755
index 2362686..0000000
Binary files a/cmd/now/now and /dev/null differ
diff --git a/cmd/sub-demo/home.html b/cmd/sub-demo/home.html
deleted file mode 100755
index 220ec05..0000000
--- a/cmd/sub-demo/home.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cmd/sub-demo/main.go b/cmd/sub-demo/main.go
deleted file mode 100755
index 7d94524..0000000
--- a/cmd/sub-demo/main.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package main
-
-import (
- "net/http"
- "os"
-
- "github.com/codegangsta/negroni"
- "github.com/jchenry/jchenry/internal/auth"
- _http "github.com/jchenry/jchenry/internal/http"
- "github.com/jchenry/jchenry/internal/payments"
-)
-
-func main() {
- auth.Init()
- StartServer()
-}
-
-func StartServer() {
- auth.PrintConfig()
- payments.PrintConfig()
-
- auth_service := auth.Service(auth.FromEnv())
- s := _http.NewServer(negroni.New(), _http.NewJulienschmidtHTTPRouter()).
- Static("/public/*filepath", http.Dir("public/")).
- Service("", auth_service).
- Service("", payments.Service(payments.FromEnv(), &auth_service)).
- Get("/", "", http.HandlerFunc(HomeHandler))
-
- port := os.Getenv("PORT")
- if port == "" {
- port = "3000"
- }
-
- s.Run(":" + port)
-}
-
-func HomeHandler(w http.ResponseWriter, r *http.Request) {
- _http.RenderTemplate(w, "home", nil)
-}
diff --git a/cmd/sub-demo/public/app.css b/cmd/sub-demo/public/app.css
deleted file mode 100755
index 5d6a003..0000000
--- a/cmd/sub-demo/public/app.css
+++ /dev/null
@@ -1,95 +0,0 @@
-body {
- font-family: "proxima-nova", sans-serif;
- text-align: center;
- font-size: 300%;
- font-weight: 100;
- }
- input[type=checkbox],
- input[type=radio] {
- position: absolute;
- opacity: 0;
- }
- input[type=checkbox] + label,
- input[type=radio] + label {
- display: inline-block;
- }
- input[type=checkbox] + label:before,
- input[type=radio] + label:before {
- content: "";
- display: inline-block;
- vertical-align: -0.2em;
- width: 1em;
- height: 1em;
- border: 0.15em solid #0074d9;
- border-radius: 0.2em;
- margin-right: 0.3em;
- background-color: white;
- }
- input[type=radio] + label:before {
- border-radius: 50%;
- }
- input[type=radio]:checked + label:before,
- input[type=checkbox]:checked + label:before {
- background-color: #0074d9;
- box-shadow: inset 0 0 0 0.15em white;
- }
- input[type=radio]:focus + label:before,
- input[type=checkbox]:focus + label:before {
- outline: 0;
- }
- .btn {
- font-size: 140%;
- text-transform: uppercase;
- letter-spacing: 1px;
- border: 0;
- background-color: #16214D;
- color: white;
- }
- .btn:hover {
- background-color: #44C7F4;
- }
- .btn:focus {
- outline: none !important;
- }
- .btn.btn-lg {
- padding: 20px 30px;
- }
- .btn:disabled {
- background-color: #333;
- color: #666;
- }
- h1,
- h2,
- h3 {
- font-weight: 100;
- }
- #logo img {
- width: 300px;
- margin-bottom: 60px;
- }
- .home-description {
- font-weight: 100;
- margin: 100px 0;
- }
- h2 {
- margin-top: 30px;
- margin-bottom: 40px;
- font-size: 200%;
- }
- label {
- font-size: 100%;
- font-weight: 300;
- }
- .btn-next {
- margin-top: 30px;
- }
- .answer {
- width: 70%;
- margin: auto;
- text-align: left;
- padding-left: 10%;
- margin-bottom: 20px;
- }
- .login-page .login-box {
- padding: 100px 0;
- }
\ No newline at end of file
diff --git a/cmd/sub-demo/run.sh b/cmd/sub-demo/run.sh
deleted file mode 100755
index c95d2ac..0000000
--- a/cmd/sub-demo/run.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-AUTH_DOMAIN="https://dev-pb4s8m55.auth0.com/" \
-AUTH_CLIENT_ID="ae1e02bTwXA35O3r3Xxk4kbRf31j5ge9" \
-AUTH_CLIENT_SECRET="NFC5KYeM9GA2z0ptvzKPo9jmkQDRjx_WcsWyK0hzOJmr1CykS9cEmTcNh0-hKiMd" \
-AUTH_CALLBACK_URL="http://localhost:3000/callback" \
-AUTH_MGMT_CLIENT_ID="0SpgXDo7HleFZ6NH9ds2t2vkntEzgYqy" \
-AUTH_MGMT_CLIENT_SECRET="DhOE1JqO7A2uosadjuyCluK5P3NlxOf4V9mPkEDy4gDO_lYnMffzYfVpgcINvzfr" \
-STRIPE_KEY="sk_test_3yIcJl5ev3WfFZ4HNbTMqWv800B26e0c4V" \
-STRIPE_PRODUCT_ID="prod_FtzugcD89mNVhp" \
-./sub-demo
\ No newline at end of file
diff --git a/cmd/sub-demo/subscription.html b/cmd/sub-demo/subscription.html
deleted file mode 100755
index f30daa1..0000000
--- a/cmd/sub-demo/subscription.html
+++ /dev/null
@@ -1,123 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{.Product.Name}}
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cmd/sub-demo/user.html b/cmd/sub-demo/user.html
deleted file mode 100755
index 78cfe44..0000000
--- a/cmd/sub-demo/user.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Welcome {{.Nickname}}
-
Logout
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cmd/today/main.go b/cmd/today/main.go
deleted file mode 100755
index a3e48c1..0000000
--- a/cmd/today/main.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package main
-
-import (
- "fmt"
- "time"
-
- "github.com/jchenry/jchenry/pkg/arvelie"
-)
-
-func main() {
- a := arvelie.FromDate(time.Now())
- fmt.Println(a)
-}
diff --git a/cmd/today/today b/cmd/today/today
deleted file mode 100755
index 796e254..0000000
Binary files a/cmd/today/today and /dev/null differ
diff --git a/cmd/web-tinkertoy/db.go b/cmd/web-tinkertoy/db.go
deleted file mode 100644
index 01a3bd9..0000000
--- a/cmd/web-tinkertoy/db.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package main
-
-import (
- "context"
- "database/sql"
- "fmt"
-
- "github.com/jchenry/jchenry/db"
- "rsc.io/dbstore"
-)
-
-type DBFunc func(db *sql.DB)
-
-type DBActor struct {
- DB *sql.DB
- ActionChan chan DBFunc
-}
-
-func (a *DBActor) Run(ctx context.Context) error {
- for {
- select {
- case f := <-a.ActionChan:
- f(a.DB)
- case <-ctx.Done():
- return ctx.Err()
- }
- }
-}
-
-func DBStoreInsert(store *dbstore.Storage, e interface{}) db.Func {
- return func(db *sql.DB) {
- err := store.Insert(db, e)
- fmt.Println(err)
- }
-}
-
-func DBStoreDelete(store *dbstore.Storage, e interface{}) db.Func {
- return func(db *sql.DB) {
- store.Delete(db, e)
- }
-}
-
-func DBStoreSelect(store *dbstore.Storage,
- err chan error,
- results chan interface{},
- ent interface{},
- query string,
- args ...interface{}) db.Func {
- return func(db *sql.DB) {
- if e := store.Select(db, ent, query, args...); e != nil {
- err <- e
- } else {
- results <- ent
- }
- }
-}
-
-func DBStoreRead(store *dbstore.Storage,
- err chan error,
- results chan interface{},
- ent interface{},
- columns ...string) db.Func {
- return func(db *sql.DB) {
- if e := store.Read(db, ent, columns...); e != nil {
- err <- e
- } else {
- results <- ent
- }
- }
-}
diff --git a/cmd/web-tinkertoy/echo.go b/cmd/web-tinkertoy/echo.go
deleted file mode 100644
index ee94fe2..0000000
--- a/cmd/web-tinkertoy/echo.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package main
-
-import (
- "net/http"
- "sync"
- "text/template"
-)
-
-func (s *server) handleEcho() http.HandlerFunc {
- var (
- init sync.Once
- tmpl *template.Template
- tplerr error
- )
- return func(w http.ResponseWriter, r *http.Request) {
- init.Do(func() {
- tmpl, tplerr = template.ParseFiles("echoform.tmpl")
- })
- if tplerr != nil {
- http.Error(w, tplerr.Error(), http.StatusInternalServerError)
- return
- }
-
- switch r.Method {
- case http.MethodPost:
- r.ParseForm()
- s.echoMessage = r.Form.Get("msg")
- http.Redirect(w, r, "/echo", 301)
- return
- case http.MethodGet:
- if err := tmpl.Execute(w, map[string]string{"Message": s.echoMessage}); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
- }
- }
-}
diff --git a/cmd/web-tinkertoy/echoform.tmpl b/cmd/web-tinkertoy/echoform.tmpl
deleted file mode 100644
index bac403f..0000000
--- a/cmd/web-tinkertoy/echoform.tmpl
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-{{if (eq .Message "")}}
-
-{{else}}
-
- {{.Message}}
-
-{{end}}
-
-
diff --git a/cmd/web-tinkertoy/foo.db b/cmd/web-tinkertoy/foo.db
deleted file mode 100644
index 9e6daf3..0000000
Binary files a/cmd/web-tinkertoy/foo.db and /dev/null differ
diff --git a/cmd/web-tinkertoy/fortune.go b/cmd/web-tinkertoy/fortune.go
deleted file mode 100644
index 2035ebb..0000000
--- a/cmd/web-tinkertoy/fortune.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package main
-
-import (
- "bufio"
- "context"
- "fmt"
- "log"
- "net/http"
- "sync"
- "text/template"
-
- "github.com/jchenry/jchenry/db"
- "rsc.io/dbstore"
-)
-
-func (s *server) handleFortune() http.HandlerFunc {
- var (
- init sync.Once
- dba *db.Actor
- storage *dbstore.Storage
- tmpl *template.Template
- tplerr error
- )
-
- type fortuneWrapper struct {
- Fortune string
- }
-
- return func(w http.ResponseWriter, r *http.Request) {
- init.Do(func() {
- ctx, _ := context.WithCancel(context.Background())
- dba = &db.Actor{
- DB: s.db,
- ActionChan: make(chan db.Func),
- }
- go dba.Run(ctx)
- storage = new(dbstore.Storage)
- storage.Register(&fortuneWrapper{})
- err := storage.CreateTables(dba.DB)
- if err != nil {
- fmt.Println(err)
- }
- tmpl, tplerr = template.ParseFiles("fortunesupload.tmpl")
- })
-
- if tplerr != nil {
- http.Error(w, tplerr.Error(), http.StatusInternalServerError)
- return
- }
-
- switch r.Method {
- case http.MethodPost:
- r.ParseMultipartForm(10 << 20)
- file, _, err := r.FormFile("fortunes")
- if err != nil {
- fmt.Println("Error Retrieving the File")
- fmt.Println(err)
- return
- }
- defer file.Close()
-
- scanner := bufio.NewScanner(file)
- var fortune string
- for scanner.Scan() {
- switch scanner.Text() {
- case "%":
- dba.ActionChan <- DBStoreInsert(storage, &fortuneWrapper{Fortune: fortune})
- default:
- fortune = scanner.Text()
- }
-
- }
-
- if err := scanner.Err(); err != nil {
- log.Fatal(err)
- }
- case http.MethodGet:
- f := fortuneWrapper{}
- results := make(chan interface{})
- err := make(chan error)
-
- dba.ActionChan <- DBStoreSelect(storage, err, results, &f, "ORDER BY RANDOM() LIMIT 1", "*")
- select {
- case r := <-results:
- if err := tmpl.Execute(w, map[string]string{"Message": r.(*fortuneWrapper).Fortune}); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
-
- case e := <-err:
- http.Error(w, e.Error(), http.StatusInternalServerError)
- }
-
- }
-
- }
-}
diff --git a/cmd/web-tinkertoy/fortunesupload.tmpl b/cmd/web-tinkertoy/fortunesupload.tmpl
deleted file mode 100644
index c374a6e..0000000
--- a/cmd/web-tinkertoy/fortunesupload.tmpl
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-{{if (eq .Message "")}}
-
-{{else}}
- {{.Message}}
-{{end}}
-
-
diff --git a/cmd/web-tinkertoy/go.mod b/cmd/web-tinkertoy/go.mod
deleted file mode 100644
index 50d51d5..0000000
--- a/cmd/web-tinkertoy/go.mod
+++ /dev/null
@@ -1,22 +0,0 @@
-module github.com/jchenry/jchenry/cmd/web-tinkertoy
-
-go 1.14
-
-require (
- github.com/codegangsta/negroni v1.0.0 // indirect
- github.com/coreos/go-oidc v2.1.0+incompatible // indirect
- github.com/gorilla/sessions v1.2.0 // indirect
- github.com/jchenry/jchenry v0.0.0-00010101000000-000000000000
- github.com/julienschmidt/httprouter v1.2.0 // indirect
- github.com/mattn/go-sqlite3 v2.0.3+incompatible
- github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
- github.com/stretchr/testify v1.4.0 // indirect
- github.com/stripe/stripe-go v63.4.0+incompatible // indirect
- golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad // indirect
- golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
- gopkg.in/auth0.v1 v1.2.7 // indirect
- gopkg.in/square/go-jose.v2 v2.3.1 // indirect
- rsc.io/dbstore v0.1.1
-)
-
-replace github.com/jchenry/jchenry => ../../
diff --git a/cmd/web-tinkertoy/go.sum b/cmd/web-tinkertoy/go.sum
deleted file mode 100644
index b8731fd..0000000
--- a/cmd/web-tinkertoy/go.sum
+++ /dev/null
@@ -1,42 +0,0 @@
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/PuerkitoBio/rehttp v0.0.0-20180310210549-11cf6ea5d3e9/go.mod h1:ItsOiHl4XeMOV3rzbZqQRjLc3QQxbE6391/9iNG7rE8=
-github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade/go.mod h1:f1P3hjG+t54/IrnXMnnw+gRmFCDR/ryj9xSQ7MPMkQw=
-github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61/go.mod h1:Rp8e0DCtEKwXFOC6JPJQVTz8tuGoGvw6Xfexggh/ed0=
-github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
-github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
-github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
-github.com/jchenry/jchenry v0.0.0-20191107034549-4697006d1099 h1:qUy+BhiLM5LzN0cOGtqvuC2v7FNfmQFg1cjZbNcMnBY=
-github.com/jchenry/jchenry v0.0.0-20191107034549-4697006d1099/go.mod h1:5ywsKLPV6YOTZ7oNNmQo7EQRDKhlGCD311r/ZRZgHDM=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c=
-github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
-github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
-github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stripe/stripe-go v63.4.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-gopkg.in/auth0.v1 v1.2.7/go.mod h1:1FRtMXwYDgygZcO7Of7kj/I4mf9UjHGhMHUOqNT0d0M=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-rsc.io/dbstore v0.1.1 h1:LI4gBJUwbejn0wHJWe0KTwgCM33zUVP3BsNz5y2fkEE=
-rsc.io/dbstore v0.1.1/go.mod h1:zI7k1PCSLg9r/T2rBM4E/SctbGmqdtt3kjQSemVh1Rs=
-rsc.io/sqlite v0.5.0/go.mod h1:fqHuveM9iIqMzjD0WiZIvKYMty/WqTo2bxE9+zC54WE=
diff --git a/cmd/web-tinkertoy/main.go b/cmd/web-tinkertoy/main.go
deleted file mode 100644
index 31c85ce..0000000
--- a/cmd/web-tinkertoy/main.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package main
-
-import (
- "database/sql"
- "fmt"
- "io"
- "net/http"
- "os"
-
- _ "github.com/mattn/go-sqlite3"
-)
-
-func main() {
- if err := run(os.Args, os.Stdout); err != nil {
- fmt.Fprintf(os.Stderr, "%s\n", err)
- os.Exit(1)
- }
-}
-
-func run(args []string, stdout io.Writer) error {
- s := server{
- router: http.NewServeMux(),
- }
-
- s.routes()
-
- if db, err := sql.Open("sqlite3", "foo.db"); err == nil {
- s.db = db
- } else {
- return err
- }
- return http.ListenAndServe(":8080", s.router)
-
-}
diff --git a/cmd/web-tinkertoy/server.go b/cmd/web-tinkertoy/server.go
deleted file mode 100644
index 7b4204e..0000000
--- a/cmd/web-tinkertoy/server.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package main
-
-import (
- "database/sql"
- "net/http"
-)
-
-type server struct {
- db *sql.DB
- router *http.ServeMux
- echoMessage string
-}
-
-func (s *server) routes() {
- s.router.HandleFunc("/time", s.handleTime())
- s.router.HandleFunc("/echo", s.handleEcho())
- s.router.HandleFunc("/fortune", s.handleFortune())
-}
diff --git a/cmd/web-tinkertoy/time.go b/cmd/web-tinkertoy/time.go
deleted file mode 100644
index 9239450..0000000
--- a/cmd/web-tinkertoy/time.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package main
-
-import (
- "fmt"
- "io"
- "net/http"
- "time"
-
- "github.com/jchenry/jchenry/arvelie"
- "github.com/jchenry/jchenry/neralie"
-)
-
-func (s *server) handleTime() http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- t := time.Now()
- w.WriteHeader(200)
- io.WriteString(w, t.String())
- io.WriteString(w, fmt.Sprintf("\n%s %s",
- arvelie.FromDate(t),
- neralie.FromTime(t)))
- }
-}
diff --git a/cmd/wiki/edit.go b/cmd/wiki/edit.go
deleted file mode 100644
index fb16702..0000000
--- a/cmd/wiki/edit.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package main
-
-import (
- "net/http"
- "os"
-)
-
-func edit(pageName string, w http.ResponseWriter, r *http.Request) (err error) {
- if body, err := getFile(pageName, os.O_RDWR|os.O_CREATE); err == nil {
- return render(pageName, "edit", body, w)
- }
- return
-}
diff --git a/cmd/wiki/http.go b/cmd/wiki/http.go
deleted file mode 100644
index 340408f..0000000
--- a/cmd/wiki/http.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package main
-
-import (
- "net/http"
- "os"
-)
-
-func auth(fn http.HandlerFunc) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- user, pass, _ := r.BasicAuth()
- if !(user == os.Getenv("WIKI_USERNAME") && pass == os.Getenv("WIKI_PASSWORD")) {
- w.Header().Set("WWW-Authenticate", `Basic realm="wiki"`)
- http.Error(w, "Unauthorized.", 401)
- return
- }
- fn(w, r)
- }
-}
diff --git a/cmd/wiki/main.go b/cmd/wiki/main.go
deleted file mode 100644
index e057c8f..0000000
--- a/cmd/wiki/main.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package main
-
-import (
- "flag"
- "log"
- "net/http"
- "os"
- "path"
- "path/filepath"
-)
-
-type actionFunc func(s string, w http.ResponseWriter, r *http.Request) error
-
-var pageDir *string
-
-func main() {
- p, err := filepath.Abs(filepath.Dir(os.Args[0]))
- if err != nil {
- panic(err)
- }
- pageDir = flag.String("pageDir", path.Join(p, "pages"), "the directory in which pages exist")
- httpAddr := flag.String("http", "127.0.0.1:8080", " HTTP service address")
- help := flag.Bool("help", false, "this help.")
- flag.Parse()
- if *help {
- flag.Usage()
- return
- }
- for path, action := range map[string]actionFunc{"/wiki/": view, "/edit/": edit, "/save/": save, "/search/": search} {
- register(path, action)
- }
- http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
- http.Handle("/", auth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { view("WelcomeVisitors", w, r) })))
- log.Printf("using log/pass: %s/%s", os.Getenv("WIKI_USERNAME"), os.Getenv("WIKI_PASSWORD"))
- log.Printf("wiki has started listening at %s", *httpAddr)
- log.Fatal(http.ListenAndServe(*httpAddr, nil))
-}
-
-func register(path string, action actionFunc) {
- http.Handle(path, http.StripPrefix(path, auth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.URL.Path != "" {
- if err := action(r.URL.Path, w, r); err != nil {
- log.Fatal(err)
- }
- }
- }))))
-}
diff --git a/cmd/wiki/os.go b/cmd/wiki/os.go
deleted file mode 100644
index 5272ee8..0000000
--- a/cmd/wiki/os.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package main
-
-import (
- "io/ioutil"
- "os"
- "path"
-)
-
-func getFile(pageName string, flags int) (file []byte, err error) {
- if f, err := os.OpenFile(path.Join(*pageDir, pageName), flags, 0755); err == nil {
- return ioutil.ReadAll(f)
- }
- return file, err
-}
-
-func saveFile(pageName string, contents []byte) error {
- return ioutil.WriteFile(path.Join(*pageDir, pageName), contents, 0700)
-}
diff --git a/cmd/wiki/render.go b/cmd/wiki/render.go
deleted file mode 100644
index 6394d12..0000000
--- a/cmd/wiki/render.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package main
-
-import (
- "net/http"
- "text/template"
-)
-
-func render(p string, m string, body []byte, w http.ResponseWriter) (err error) {
- if tmpl, err := template.ParseFiles("page.tmpl.html"); err == nil {
- return tmpl.Execute(w, struct {
- Mode string
- Body string
- Page string
- }{m, string(body), p})
- }
- return err
-}
diff --git a/cmd/wiki/save.go b/cmd/wiki/save.go
deleted file mode 100644
index 2d33fd7..0000000
--- a/cmd/wiki/save.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package main
-
-import (
- "fmt"
- "net/http"
-)
-
-func save(pageName string, w http.ResponseWriter, r *http.Request) (err error) {
- r.ParseForm()
- if err = saveFile(pageName, []byte(r.Form.Get("Text"))); err == nil {
- http.Redirect(w, r, fmt.Sprintf("/wiki/%s", pageName), http.StatusTemporaryRedirect)
- }
- return
-}
diff --git a/cmd/wiki/search.go b/cmd/wiki/search.go
deleted file mode 100644
index 9f1eb91..0000000
--- a/cmd/wiki/search.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package main
-
-import (
- "fmt"
- "io/ioutil"
- "net/http"
- "os"
- "regexp"
-)
-
-const resultFmt = "%s . . . . . . %s \n"
-
-func search(keyword string, w http.ResponseWriter, r *http.Request) (err error) {
- var results string
- if files, err := ioutil.ReadDir(*pageDir); err == nil {
- re := regexp.MustCompile(keyword)
- for _, f := range files {
- if f.Name() == keyword {
- results += fmt.Sprintf(resultFmt, f.Name(), f.Name(), f.Name())
- }
- if body, err := getFile(f.Name(), os.O_RDWR); err == nil {
- for _, occur := range re.FindSubmatch(body) {
- results += fmt.Sprintf(resultFmt, f.Name(), f.Name(), occur)
- }
- } else {
- return err
- }
- }
- render("search", "view", []byte(results), w)
- }
- return err
-}
diff --git a/cmd/wiki/view.go b/cmd/wiki/view.go
deleted file mode 100644
index 24bc2fa..0000000
--- a/cmd/wiki/view.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package main
-
-import (
- "bytes"
- "fmt"
- "net/http"
- "os"
- "regexp"
- "strings"
-
- "github.com/russross/blackfriday/v2"
-)
-
-var patterns [5]*regexp.Regexp
-var renderers [5]func([]byte) []byte
-
-func init() {
- // /*autoLinkRegexp*/ patterns[0], renderers[0] = regexp.MustCompile("[A-Z][a-z0-9]+([A-Z][a-z0-9]+)+"), func(s []byte) []byte { return []byte(fmt.Sprintf(`%s `, string(s), string(s))) }
- /*BracketedAutoLinkRegexp*/
- patterns[0], renderers[0] = regexp.MustCompile("\\[\\[[A-Za-z0-9 ]+([A-Za-z0-9 ]+)+\\]\\]"), func(s []byte) []byte { return []byte(fmt.Sprintf(`%s `, string(s), string(s))) }
-
- /*searchRegexp*/
- patterns[1], renderers[1] = regexp.MustCompile("\\[Search\\]"), func(s []byte) []byte {
- return []byte(``)
- }
- /*youTubeLinkRegexp*/ patterns[2], renderers[2] = regexp.MustCompile("https://(www.)?youtube.com/watch\\?v=([-\\w]+)"), func(s []byte) []byte {
- return []byte(fmt.Sprintf(``, strings.Split(string(s), "=")[1]))
- }
- /*isbnLinkRegexp*/ patterns[3], renderers[3] = regexp.MustCompile("ISBN:*([0-9]{10,})"), func(s []byte) []byte {
- return []byte(fmt.Sprintf(`ISBN %s `, bytes.Replace(bytes.Split(s, []byte(":"))[1], []byte("-"), []byte(""), -1), bytes.Split(s, []byte(":"))[1]))
- }
- /*alltextRegexp*/ patterns[4], renderers[4] = regexp.MustCompile(".*"), func(s []byte) []byte {
- return blackfriday.Run(s, blackfriday.WithExtensions(blackfriday.CommonExtensions))
- }
-}
-
-func view(pageName string, w http.ResponseWriter, r *http.Request) (err error) {
- var body []byte
- if body, err = getFile(pageName, os.O_RDWR); os.IsNotExist(err) {
- http.Redirect(w, r, fmt.Sprintf("/edit/%s", pageName), http.StatusTemporaryRedirect) // no page? redirect to edit/create it.
- return nil
- }
- for i := range renderers {
- body = patterns[i].ReplaceAllFunc(body, renderers[i])
- }
- return render(pageName, "view", body, w)
-}
diff --git a/pkg/db/actor.go b/database/actor.go
similarity index 94%
rename from pkg/db/actor.go
rename to database/actor.go
index 0604597..ab7f6dc 100644
--- a/pkg/db/actor.go
+++ b/database/actor.go
@@ -1,4 +1,4 @@
-package db
+package database
import (
"context"
diff --git a/pkg/db/doc.go b/database/doc.go
similarity index 79%
rename from pkg/db/doc.go
rename to database/doc.go
index d1d9b18..8241f01 100644
--- a/pkg/db/doc.go
+++ b/database/doc.go
@@ -1,14 +1,15 @@
-package db
+package database
+
/*
-Example usage:
-
+Example usage:
+
ctx, _ := context.WithCancel(context.Background())
dba = &db.Actor{
DB: s.db,
ActionChan: make(chan db.Func),
}
-
+
go dba.Run(ctx)
-*/
\ No newline at end of file
+*/
diff --git a/encoding/coder.go b/encoding/coder.go
new file mode 100644
index 0000000..c98a057
--- /dev/null
+++ b/encoding/coder.go
@@ -0,0 +1,6 @@
+package encoding
+
+import "io"
+
+type Encoder func(io.Writer, interface{}) error
+type Decoder func(io.Reader, interface{}) error
diff --git a/encoding/json/json.go b/encoding/json/json.go
new file mode 100644
index 0000000..3d5eb8d
--- /dev/null
+++ b/encoding/json/json.go
@@ -0,0 +1,23 @@
+package json
+
+import (
+ "encoding/json"
+ "io"
+)
+
+func Encoder(w io.Writer, e interface{}) error {
+ return json.NewEncoder(w).Encode(e)
+}
+
+func Decoder(r io.Reader, e interface{}) error {
+ return json.NewDecoder(r).Decode(e)
+}
+
+// func Decoder(get func() interface{}) func(io.Reader) (interface{}, error) {
+// //TODO I dont like the get() function, find a better way of dealing with this
+// return func(r io.Reader) (interface{}, error) {
+// e := get()
+// err := json.NewDecoder(r).Decode(e)
+// return e, err
+// }
+// }
diff --git a/encoding/xml/xml.go b/encoding/xml/xml.go
new file mode 100644
index 0000000..5dd563e
--- /dev/null
+++ b/encoding/xml/xml.go
@@ -0,0 +1,24 @@
+package xml
+
+import (
+ "encoding/xml"
+ "io"
+)
+
+func Encoder(w io.Writer, e interface{}) error {
+ return xml.NewEncoder(w).Encode(e)
+}
+
+func Decoder(r io.Reader, e interface{}) error {
+ return xml.NewDecoder(r).Decode(e)
+}
+
+// func Decoder(get func() interface{}) func(io.Reader) (interface{}, error) {
+// //TODO I dont like the get() function, find a better way of dealing with this
+// return func(r io.Reader) (interface{}, error) {
+// e := get()
+// err := xml.NewDecoder(r).Decode(e)
+// return e, err
+// }
+// }
+//
diff --git a/go.mod b/go.mod
index bf150d6..a9d17b2 100755
--- a/go.mod
+++ b/go.mod
@@ -1,21 +1,22 @@
-module github.com/jchenry/jchenry
+module github.com/jchenry/x
go 1.13
require (
+ fyne.io/fyne v1.3.0
github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade
github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 // indirect
github.com/codegangsta/negroni v1.0.0
github.com/coreos/go-oidc v2.1.0+incompatible
github.com/gorilla/sessions v1.2.0
+ github.com/jchenry/jchenry v0.0.0-20200615172632-cb0bc37e6b16
github.com/julienschmidt/httprouter v1.2.0
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/rsc/rsc v0.0.0-20180427141835-fc6202590229
github.com/russross/blackfriday/v2 v2.0.1
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
- github.com/stretchr/testify v1.4.0 // indirect
github.com/stripe/stripe-go v63.4.0+incompatible
- golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad // indirect
+ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
gopkg.in/auth0.v1 v1.2.7
gopkg.in/square/go-jose.v2 v2.3.1 // indirect
diff --git a/go.sum b/go.sum
index 7e46086..60e204b 100755
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,12 @@
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+fyne.io/fyne v1.3.0 h1:FLlgX/JkD3Chal7tEhRL7fOONVAjQJM/yrVNA+cK/dc=
+fyne.io/fyne v1.3.0/go.mod h1:AcBUeR8hetITnnfaLvuVqioWM/lT18WPeMVAobhMbg8=
+github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
github.com/PuerkitoBio/rehttp v0.0.0-20180310210549-11cf6ea5d3e9 h1:VE0eMvNSQI72dADsq4gm5KpNPmt97WgqneTfaS5MWrs=
github.com/PuerkitoBio/rehttp v0.0.0-20180310210549-11cf6ea5d3e9/go.mod h1:ItsOiHl4XeMOV3rzbZqQRjLc3QQxbE6391/9iNG7rE8=
github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade h1:odEkSCl2gLWPtvraEdCyBZbeYyMMTysWPLMurnB8sUY=
github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade/go.mod h1:f1P3hjG+t54/IrnXMnnw+gRmFCDR/ryj9xSQ7MPMkQw=
+github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 h1:o64h9XF42kVEUuhuer2ehqrlX8rZmvQSU0+Vpj1rF6Q=
github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61/go.mod h1:Rp8e0DCtEKwXFOC6JPJQVTz8tuGoGvw6Xfexggh/ed0=
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
@@ -11,14 +15,39 @@ github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fyne-io/mobile v0.0.2 h1:eGmCR5lkFxk0PnPafGppLFRD5QODJfSVdrjhLjanOVg=
+github.com/fyne-io/mobile v0.0.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
+github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw=
+github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
+github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
+github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
+github.com/jchenry/jchenry v0.0.0-20200615172632-cb0bc37e6b16 h1:vVomaWqIbI/Vyb6uGE8ANmF8V3ktoLiOXdcKQLvwUc4=
+github.com/jchenry/jchenry v0.0.0-20200615172632-cb0bc37e6b16/go.mod h1:WLNY6BKAzrUIfnkPA8WCUxkKchKZss4fRSVmbKZuhMg=
+github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng=
+github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
@@ -30,38 +59,75 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM=
+github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
+github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM=
+github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stripe/stripe-go v63.4.0+incompatible h1:zzZR004GZ/si7nyckn4NBhoQOViUu5VJ/sA7NT7oTSs=
github.com/stripe/stripe-go v63.4.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
+golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
+golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/auth0.v1 v1.2.7 h1:9UCE5rKFL60rqQENmmJaGdNu7/aby8r8wVcJ83Vj5oU=
gopkg.in/auth0.v1 v1.2.7/go.mod h1:1FRtMXwYDgygZcO7Of7kj/I4mf9UjHGhMHUOqNT0d0M=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
rsc.io/dbstore v0.1.1 h1:LI4gBJUwbejn0wHJWe0KTwgCM33zUVP3BsNz5y2fkEE=
rsc.io/dbstore v0.1.1/go.mod h1:zI7k1PCSLg9r/T2rBM4E/SctbGmqdtt3kjQSemVh1Rs=
rsc.io/rsc v0.0.0-20180427141835-fc6202590229 h1:6s5zUknxnRp4D3GlNb7uDzlcfFVq9G2ficO+k4Bcb6w=
diff --git a/internal/auth/auth.go b/internal/auth/auth.go
index 8463a2b..5f9c34b 100755
--- a/internal/auth/auth.go
+++ b/internal/auth/auth.go
@@ -1,40 +1,40 @@
package auth
-import (
- "context"
- "log"
+// import (
+// "context"
+// "log"
- "golang.org/x/oauth2"
+// "golang.org/x/oauth2"
- oidc "github.com/coreos/go-oidc"
-)
+// oidc "github.com/coreos/go-oidc"
+// )
-type Authenticator struct {
- Provider *oidc.Provider
- Config oauth2.Config
- Ctx context.Context
-}
+// type Authenticator struct {
+// Provider *oidc.Provider
+// Config oauth2.Config
+// Ctx context.Context
+// }
-func NewAuthenticator(domain, clientID, clientSecret, callback string) (*Authenticator, error) {
- ctx := context.Background()
+// func NewAuthenticator(domain, clientID, clientSecret, callback string) (*Authenticator, error) {
+// ctx := context.Background()
- provider, err := oidc.NewProvider(ctx, domain)
- if err != nil {
- log.Printf("failed to get provider: %v", err)
- return nil, err
- }
+// provider, err := oidc.NewProvider(ctx, domain)
+// if err != nil {
+// log.Printf("failed to get provider: %v", err)
+// return nil, err
+// }
- conf := oauth2.Config{
- ClientID: clientID,
- ClientSecret: clientSecret,
- RedirectURL: callback,
- Endpoint: provider.Endpoint(),
- Scopes: []string{oidc.ScopeOpenID, "profile"},
- }
+// conf := oauth2.Config{
+// ClientID: clientID,
+// ClientSecret: clientSecret,
+// RedirectURL: callback,
+// Endpoint: provider.Endpoint(),
+// Scopes: []string{oidc.ScopeOpenID, "profile"},
+// }
- return &Authenticator{
- Provider: provider,
- Config: conf,
- Ctx: ctx,
- }, nil
-}
+// return &Authenticator{
+// Provider: provider,
+// Config: conf,
+// Ctx: ctx,
+// }, nil
+// }
diff --git a/internal/auth/callback.go b/internal/auth/callback.go
index 06266b6..9fcf46f 100755
--- a/internal/auth/callback.go
+++ b/internal/auth/callback.go
@@ -1,89 +1,89 @@
package auth
-import (
- "context"
- "log"
- "net/http"
+// import (
+// "context"
+// "log"
+// "net/http"
- oidc "github.com/coreos/go-oidc"
-)
+// oidc "github.com/coreos/go-oidc"
+// )
-func NewCallbackHandler(c Config) http.HandlerFunc {
+// func NewCallbackHandler(c Config) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- session, err := Store.Get(r, SessionName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// return func(w http.ResponseWriter, r *http.Request) {
+// session, err := Store.Get(r, SessionName)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- if r.URL.Query().Get("state") != session.Values["state"] {
- http.Error(w, "Invalid state parameter", http.StatusBadRequest)
- return
- }
+// if r.URL.Query().Get("state") != session.Values["state"] {
+// http.Error(w, "Invalid state parameter", http.StatusBadRequest)
+// return
+// }
- authenticator, err := NewAuthenticator(c.Domain, c.ClientID, c.ClientSecret, c.CallbackURL)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// authenticator, err := NewAuthenticator(c.Domain, c.ClientID, c.ClientSecret, c.CallbackURL)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- token, err := authenticator.Config.Exchange(context.TODO(), r.URL.Query().Get("code"))
- if err != nil {
- log.Printf("no token found: %v", err)
- w.WriteHeader(http.StatusUnauthorized)
- return
- }
+// token, err := authenticator.Config.Exchange(context.TODO(), r.URL.Query().Get("code"))
+// if err != nil {
+// log.Printf("no token found: %v", err)
+// w.WriteHeader(http.StatusUnauthorized)
+// return
+// }
- rawIDToken, ok := token.Extra("id_token").(string)
- if !ok {
- http.Error(w, "No id_token field in oauth2 token.", http.StatusInternalServerError)
- return
- }
+// rawIDToken, ok := token.Extra("id_token").(string)
+// if !ok {
+// http.Error(w, "No id_token field in oauth2 token.", http.StatusInternalServerError)
+// return
+// }
- oidcConfig := &oidc.Config{
- ClientID: c.ClientID,
- }
+// oidcConfig := &oidc.Config{
+// ClientID: c.ClientID,
+// }
- idToken, err := authenticator.Provider.Verifier(oidcConfig).Verify(context.TODO(), rawIDToken)
+// idToken, err := authenticator.Provider.Verifier(oidcConfig).Verify(context.TODO(), rawIDToken)
- if err != nil {
- http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError)
- return
- }
+// if err != nil {
+// http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError)
+// return
+// }
- // Getting now the userInfo
- user := User{}
- if err := idToken.Claims(&user); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// // Getting now the userInfo
+// user := User{}
+// if err := idToken.Claims(&user); err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- session.Values["id_token"] = rawIDToken
- session.Values["access_token"] = token.AccessToken
- session.Values["profile"] = user
- err = session.Save(r, w)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// session.Values["id_token"] = rawIDToken
+// session.Values["access_token"] = token.AccessToken
+// session.Values["profile"] = user
+// err = session.Save(r, w)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- // if application ID is non existent, and therefore does not have a tenant
- // Create or associate?
- // Create:
- // - Create Tenant
- // - Specify plan
- // - Specify payment info
- // - Associate Tenant
- // - by email address domain?
- //set tenant ID on application ID in App Metadata on user
+// // if application ID is non existent, and therefore does not have a tenant
+// // Create or associate?
+// // Create:
+// // - Create Tenant
+// // - Specify plan
+// // - Specify payment info
+// // - Associate Tenant
+// // - by email address domain?
+// //set tenant ID on application ID in App Metadata on user
- // if c.CallbackFunc != nil {
- // c.CallbackFunc(c, user)
- // } else {
- // Redirect to logged in page
- http.Redirect(w, r, c.RedirectURL, http.StatusSeeOther)
- // }
+// // if c.CallbackFunc != nil {
+// // c.CallbackFunc(c, user)
+// // } else {
+// // Redirect to logged in page
+// http.Redirect(w, r, c.RedirectURL, http.StatusSeeOther)
+// // }
- }
-}
+// }
+// }
diff --git a/internal/auth/config.go b/internal/auth/config.go
index e53329c..4c8eb4f 100755
--- a/internal/auth/config.go
+++ b/internal/auth/config.go
@@ -1,36 +1,36 @@
package auth
-import (
- "fmt"
- "os"
-)
+// import (
+// "fmt"
+// "os"
+// )
-type Config struct {
- Domain string
- ClientID string
- ClientSecret string
- ManagementClientID string
- ManagementClientSecret string
+// type Config struct {
+// Domain string
+// ClientID string
+// ClientSecret string
+// ManagementClientID string
+// ManagementClientSecret string
- CallbackURL string
- RedirectURL string
-}
+// CallbackURL string
+// RedirectURL string
+// }
-func FromEnv() Config {
- return Config{
- Domain: os.Getenv("AUTH_DOMAIN"),
- ClientID: os.Getenv("AUTH_CLIENT_ID"),
- ClientSecret: os.Getenv("AUTH_CLIENT_SECRET"),
- ManagementClientID: os.Getenv("AUTH_MGMT_CLIENT_ID"),
- ManagementClientSecret: os.Getenv("AUTH_MGMT_CLIENT_SECRET"),
+// func FromEnv() Config {
+// return Config{
+// Domain: os.Getenv("AUTH_DOMAIN"),
+// ClientID: os.Getenv("AUTH_CLIENT_ID"),
+// ClientSecret: os.Getenv("AUTH_CLIENT_SECRET"),
+// ManagementClientID: os.Getenv("AUTH_MGMT_CLIENT_ID"),
+// ManagementClientSecret: os.Getenv("AUTH_MGMT_CLIENT_SECRET"),
- CallbackURL: os.Getenv("AUTH_CALLBACK_URL"),
- RedirectURL: "/user",
- }
-}
+// CallbackURL: os.Getenv("AUTH_CALLBACK_URL"),
+// RedirectURL: "/user",
+// }
+// }
-func PrintConfig() {
- fmt.Printf("%#v\n", FromEnv())
-}
+// func PrintConfig() {
+// fmt.Printf("%#v\n", FromEnv())
+// }
-type CallbackFunc func(c Config, u User) error
+// type CallbackFunc func(c Config, u User) error
diff --git a/internal/auth/login.go b/internal/auth/login.go
index 5312158..7f4c0f2 100755
--- a/internal/auth/login.go
+++ b/internal/auth/login.go
@@ -2,42 +2,42 @@
package auth
-import (
- "crypto/rand"
- "encoding/base64"
- "net/http"
-)
+// import (
+// "crypto/rand"
+// "encoding/base64"
+// "net/http"
+// )
-func NewLoginHandler(c Config) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- // Generate random state
- b := make([]byte, 32)
- _, err := rand.Read(b)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- state := base64.StdEncoding.EncodeToString(b)
+// func NewLoginHandler(c Config) http.HandlerFunc {
+// return func(w http.ResponseWriter, r *http.Request) {
+// // Generate random state
+// b := make([]byte, 32)
+// _, err := rand.Read(b)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
+// state := base64.StdEncoding.EncodeToString(b)
- session, err := Store.Get(r, SessionName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- session.Values["state"] = state
- err = session.Save(r, w)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// session, err := Store.Get(r, SessionName)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
+// session.Values["state"] = state
+// err = session.Save(r, w)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- authenticator, err := NewAuthenticator(c.Domain, c.ClientID, c.ClientSecret, c.CallbackURL)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// authenticator, err := NewAuthenticator(c.Domain, c.ClientID, c.ClientSecret, c.CallbackURL)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- http.Redirect(w, r, authenticator.Config.AuthCodeURL(state), http.StatusTemporaryRedirect)
- }
+// http.Redirect(w, r, authenticator.Config.AuthCodeURL(state), http.StatusTemporaryRedirect)
+// }
-}
+// }
diff --git a/internal/auth/logout.go b/internal/auth/logout.go
index 497851a..9e4860f 100755
--- a/internal/auth/logout.go
+++ b/internal/auth/logout.go
@@ -1,43 +1,43 @@
package auth
-import (
- "net/http"
- "net/url"
-)
+// import (
+// "net/http"
+// "net/url"
+// )
-func LogoutHandler(w http.ResponseWriter, r *http.Request) {
+// func LogoutHandler(w http.ResponseWriter, r *http.Request) {
- if cook, err := r.Cookie(SessionName); err == nil {
- cook.MaxAge = -1
- http.SetCookie(w, cook)
- }
+// if cook, err := r.Cookie(SessionName); err == nil {
+// cook.MaxAge = -1
+// http.SetCookie(w, cook)
+// }
- domain := "dev-pb4s8m55.auth0.com"
+// domain := "dev-pb4s8m55.auth0.com"
- // var Url *url.URL
- URL, err := url.Parse("https://" + domain)
+// // var Url *url.URL
+// URL, err := url.Parse("https://" + domain)
- if err != nil {
- panic(err.Error())
- }
+// if err != nil {
+// panic(err.Error())
+// }
- session, err := Store.Get(r, SessionName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- session.Options.MaxAge = -1
+// session, err := Store.Get(r, SessionName)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
+// session.Options.MaxAge = -1
- err = session.Save(r, w)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
+// err = session.Save(r, w)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// }
- URL.Path += "/v2/logout"
- parameters := url.Values{}
- parameters.Add("returnTo", "http://localhost:3000")
- parameters.Add("client_id", "ae1e02bTwXA35O3r3Xxk4kbRf31j5ge9")
- URL.RawQuery = parameters.Encode()
+// URL.Path += "/v2/logout"
+// parameters := url.Values{}
+// parameters.Add("returnTo", "http://localhost:3000")
+// parameters.Add("client_id", "ae1e02bTwXA35O3r3Xxk4kbRf31j5ge9")
+// URL.RawQuery = parameters.Encode()
- http.Redirect(w, r, URL.String(), http.StatusTemporaryRedirect)
-}
+// http.Redirect(w, r, URL.String(), http.StatusTemporaryRedirect)
+// }
diff --git a/internal/auth/middleware.go b/internal/auth/middleware.go
index 4e918b8..2df42ab 100755
--- a/internal/auth/middleware.go
+++ b/internal/auth/middleware.go
@@ -1,19 +1,19 @@
package auth
-import "net/http"
+// import "net/http"
-func IsAuthenticated(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+// func IsAuthenticated(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
- session, err := Store.Get(r, SessionName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// session, err := Store.Get(r, SessionName)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- if _, ok := session.Values["profile"]; !ok {
- //TODO allow customization of redirect
- http.Redirect(w, r, "/", http.StatusSeeOther)
- } else {
- next(w, r)
- }
-}
+// if _, ok := session.Values["profile"]; !ok {
+// //TODO allow customization of redirect
+// http.Redirect(w, r, "/", http.StatusSeeOther)
+// } else {
+// next(w, r)
+// }
+// }
diff --git a/internal/auth/service.go b/internal/auth/service.go
index 21afd76..2a993f9 100755
--- a/internal/auth/service.go
+++ b/internal/auth/service.go
@@ -1,39 +1,38 @@
package auth
-import (
- "net/http"
+// import (
+// "github.com/jchenry/x/internal/http"
+// )
- "github.com/codegangsta/negroni"
- _http "github.com/jchenry/jchenry/internal/http"
- "gopkg.in/auth0.v1/management"
-)
+// func Service(c Config) ServiceInstance {
+// return ServiceInstance{c: c}
+// }
-func Service(c Config) ServiceInstance {
- return ServiceInstance{c: c}
-}
+// type ServiceInstance struct {
+// c Config
+// }
-type ServiceInstance struct {
- c Config
-}
+// func (si ServiceInstance) Register(m *http.Mux) {
+// }
-func (si ServiceInstance) Register(uriBase string, s *_http.Server) {
+// func (si ServiceInstance) Register(uriBase string, s *_http.Server) {
- s.Get(uriBase+"/login", "login endpoint", http.HandlerFunc(NewLoginHandler(si.c)))
- s.Get(uriBase+"/logout", "logout endpoint", http.HandlerFunc(LogoutHandler))
- s.Get(uriBase+"/callback", "oidc callback", http.HandlerFunc(NewCallbackHandler(si.c)))
- s.Get(uriBase+"/user", "user info endpoint", negroni.New(
- negroni.HandlerFunc(IsAuthenticated),
- negroni.Wrap(http.HandlerFunc(UserHandler)),
- ))
-}
+// s.Get(uriBase+"/login", "login endpoint", http.HandlerFunc(NewLoginHandler(si.c)))
+// s.Get(uriBase+"/logout", "logout endpoint", http.HandlerFunc(LogoutHandler))
+// s.Get(uriBase+"/callback", "oidc callback", http.HandlerFunc(NewCallbackHandler(si.c)))
+// s.Get(uriBase+"/user", "user info endpoint", negroni.New(
+// negroni.HandlerFunc(IsAuthenticated),
+// negroni.Wrap(http.HandlerFunc(UserHandler)),
+// ))
+// }
-func (si ServiceInstance) UpdateUser(u User) error {
- m, err := management.New(si.c.Domain, si.c.ManagementClientID, si.c.ManagementClientSecret)
- if err != nil {
- return err
- }
+// func (si ServiceInstance) UpdateUser(u User) error {
+// m, err := management.New(si.c.Domain, si.c.ManagementClientID, si.c.ManagementClientSecret)
+// if err != nil {
+// return err
+// }
- um := management.NewUserManager(m)
+// um := management.NewUserManager(m)
- return um.Update(u.ID, &management.User{AppMetadata: u.Apps})
-}
+// return um.Update(u.ID, &management.User{AppMetadata: u.Apps})
+// }
diff --git a/internal/auth/session.go b/internal/auth/session.go
index 287d1b7..d237604 100755
--- a/internal/auth/session.go
+++ b/internal/auth/session.go
@@ -1,19 +1,19 @@
package auth
-import (
- "encoding/gob"
+// import (
+// "encoding/gob"
- "github.com/gorilla/sessions"
-)
+// "github.com/gorilla/sessions"
+// )
-const SessionName = "auth-session"
+// const SessionName = "auth-session"
-var (
- Store *sessions.FilesystemStore
-)
+// var (
+// Store *sessions.FilesystemStore
+// )
-func Init() error {
- Store = sessions.NewFilesystemStore("", []byte("something-very-secret"))
- gob.Register(User{})
- return nil
-}
+// func Init() error {
+// Store = sessions.NewFilesystemStore("", []byte("something-very-secret"))
+// gob.Register(User{})
+// return nil
+// }
diff --git a/internal/auth/user.go b/internal/auth/user.go
index 98b5741..bb5dc3e 100755
--- a/internal/auth/user.go
+++ b/internal/auth/user.go
@@ -1,28 +1,28 @@
package auth
-import (
- "net/http"
+// import (
+// "net/http"
- jchenry_http "github.com/jchenry/jchenry/internal/http"
-)
+// jchenry_http "github.com/jchenry/x/internal/http"
+// )
-func UserHandler(w http.ResponseWriter, r *http.Request) {
+// func UserHandler(w http.ResponseWriter, r *http.Request) {
- session, err := Store.Get(r, SessionName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// session, err := Store.Get(r, SessionName)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- jchenry_http.RenderTemplate(w, "user", session.Values["profile"])
-}
+// jchenry_http.RenderTemplate(w, "user", session.Values["profile"])
+// }
-type User struct {
- ID string `json:"sub"`
- Email string `json:"email"`
- FirstName string `json:"given_name"`
- LastName string `json:"family_name"`
- Picture string `json:"picture"`
- Nickname string `json:"nickname"`
- Apps map[string]interface{} `json:"app_metadata,omitempty"`
-}
+// type User struct {
+// ID string `json:"sub"`
+// Email string `json:"email"`
+// FirstName string `json:"given_name"`
+// LastName string `json:"family_name"`
+// Picture string `json:"picture"`
+// Nickname string `json:"nickname"`
+// Apps map[string]interface{} `json:"app_metadata,omitempty"`
+// }
diff --git a/internal/crud/service.go b/internal/crud/service.go
index 5618f2d..22ad748 100644
--- a/internal/crud/service.go
+++ b/internal/crud/service.go
@@ -1,8 +1,6 @@
package crud
-import (
- "github.com/jchenry/jchenry/pkg/db"
-)
+import "github.com/jchenry/jchenry/pkg/db"
type Service interface {
// Find returns a pointer to an array of the results found based on params
diff --git a/internal/gopher/client.go b/internal/gopher/client.go
new file mode 100644
index 0000000..4762e24
--- /dev/null
+++ b/internal/gopher/client.go
@@ -0,0 +1,79 @@
+package gopher
+
+import (
+ "bufio"
+ "bytes"
+ "net"
+ "sync"
+)
+
+const (
+ // RFC 1436 types
+ Text byte = '0'
+ Submenu byte = '1'
+ Nameserver byte = '2'
+ Error byte = '3'
+ Binhex byte = '4'
+ DOS byte = '5'
+ UUencode byte = '6'
+ Search byte = '7'
+ Telnet byte = '8'
+ Binary byte = '9'
+ Mirror byte = '+'
+ Gif byte = 'g'
+ Image byte = 'I'
+ Telnet3270 byte = 'T'
+
+ // UnRFC'd Extensions
+ Doc byte = 'd'
+ Html byte = 'h'
+ Info byte = 'i'
+ Sound byte = 's'
+)
+
+type Client struct {
+ Socket net.Conn
+ in *bufio.Reader
+ out *bufio.Writer
+ init sync.Once
+}
+
+func (c *Client) Select(selector string) (m Menu, err error) {
+ c.init.Do(func() {
+ c.in = bufio.NewReader(c.Socket)
+ c.out = bufio.NewWriter(c.Socket)
+ })
+ c.out.WriteString(selector)
+
+ for {
+ if l, _, err := c.in.ReadLine(); err == nil {
+ s := Selector{}
+ s.Type = l[0]
+ bs := bytes.Split(l[1:], []byte{'\t'})
+ s.Display = string(bs[0])
+ s.Path = string(bs[1])
+ s.Hostname = string(bytes.Join(bs[2:3], []byte{':'}))
+ m = append(m, s)
+ } else {
+ break
+ }
+ }
+
+ // s := Selector{
+ // Type: Text,
+ // Display: "",
+ // Hostname: "",
+ // Path: "",
+ // }
+ return Menu{}, nil
+}
+
+type Menu []Selector
+
+type Selector struct {
+ Type byte
+ Display string
+ Path string
+ Hostname string
+ Port string
+}
diff --git a/internal/http/error.go b/internal/http/error.go
new file mode 100644
index 0000000..a36f17f
--- /dev/null
+++ b/internal/http/error.go
@@ -0,0 +1,14 @@
+package http
+
+import "net/http"
+
+// Error is an error wrapper for the standard HTTP error codes
+type Error int
+
+func (e Error) Error() string {
+ return http.StatusText(int(e))
+}
+
+func (e Error) Code() int {
+ return int(e)
+}
diff --git a/internal/http/mux.go b/internal/http/mux.go
new file mode 100644
index 0000000..ff066a2
--- /dev/null
+++ b/internal/http/mux.go
@@ -0,0 +1,8 @@
+package http
+
+import "net/http"
+
+type Mux interface {
+ Handle(pattern string, handler http.Handler)
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+}
diff --git a/internal/http/server.go b/internal/http/server.go
index 5c6063f..363b0a9 100755
--- a/internal/http/server.go
+++ b/internal/http/server.go
@@ -1,7 +1,8 @@
package http
import (
- "log"
+
+ // "log"
"net/http"
go_http "net/http"
)
@@ -17,86 +18,87 @@ type Router interface {
AddHandler(method, path string, handler go_http.Handler)
}
-type Service interface {
- Register(uriBase string, restServer *Server)
-}
+// type Service interface {
+// Register(uriBase string, restServer *Server)
+// }
-type ServiceFunc func(uriBase string, restServer *Server)
+// type ServiceFunc func(uriBase string, restServer *Server)
-func (f ServiceFunc) Register(uriBase string, restServer *Server) {
- f(uriBase, restServer)
-}
+// func (f ServiceFunc) Register(uriBase string, restServer *Server) {
+// f(uriBase, restServer)
+// }
-var docString = "%s \t%s\t- %s"
+// var docString = "%s \t%s\t- %s"
type Server struct {
router Router
middleware Middleware
}
-func NewServer(m Middleware, r Router) *Server {
- s := &Server{
- router: r,
- middleware: m,
- }
+// func NewServer(m Middleware, r Router) *Server {
+// s := &Server{
+// router: r,
+// middleware: m,
+// }
- s.middleware.UseHandler(s.router)
+// s.middleware.UseHandler(s.router)
- return s
-}
+// return s
+// }
func (r *Server) Get(path string, documentation string, handle go_http.Handler) *Server {
r.handle("GET", path, documentation, handle)
return r
}
-func (r *Server) Patch(path string, documentation string, handle go_http.Handler) *Server {
- r.handle("PATCH", path, documentation, handle)
- return r
-}
+// func (r *Server) Patch(path string, documentation string, handle go_http.Handler) *Server {
+// r.handle("PATCH", path, documentation, handle)
+
+// return r
+// }
func (r *Server) Post(path string, documentation string, handle go_http.Handler) *Server {
r.handle("POST", path, documentation, handle)
-
return r
}
-func (r *Server) Put(path string, documentation string, handle go_http.Handler) *Server {
- r.handle("PUT", path, documentation, handle)
- return r
-}
-func (r *Server) Delete(path string, documentation string, handle go_http.Handler) *Server {
- r.handle("DELETE", path, documentation, handle)
+// func (r *Server) Put(path string, documentation string, handle go_http.Handler) *Server {
+// r.handle("PUT", path, documentation, handle)
- return r
-}
+// return r
+// }
+// func (r *Server) Delete(path string, documentation string, handle go_http.Handler) *Server {
+// r.handle("DELETE", path, documentation, handle)
+
+// return r
+// }
func (r *Server) handle(method, path string, documentation string, handler go_http.Handler) {
- log.Printf(docString, method, path, documentation)
+ // log.Printf(docString, method, path, documentation)
r.router.AddHandler(method, path, handler)
}
-func (r *Server) Banner(banner string) *Server {
- log.Printf(banner)
- return r
-}
+// func (r *Server) Banner(banner string) *Server {
+// log.Printf(banner)
+// return r
+// }
-func (r *Server) Service(basePath string, service Service) *Server {
- service.Register(basePath, r)
- return r
-}
-func (r *Server) Static(path string, root go_http.FileSystem) *Server {
- r.router.ServeFiles(path, root)
- return r
-}
-func (r *Server) Middleware(handler go_http.Handler) *Server {
- r.middleware.UseHandler(handler)
- return r
-}
+// func (r *Server) Service(basePath string, service Service) *Server {
+// service.Register(basePath, r)
+// return r
+// }
+// func (r *Server) Static(path string, root go_http.FileSystem) *Server {
+// r.router.ServeFiles(path, root)
+// return r
+// }
+// func (r *Server) Middleware(handler go_http.Handler) *Server {
+// r.middleware.UseHandler(handler)
+// return r
+// }
-func (r *Server) Run(addr string) {
- log.Printf("listening on %s", addr)
- log.Fatal(http.ListenAndServe(addr, r.middleware))
-}
+// func (r *Server) Run(addr string) {
+// log.Printf("listening on %s", addr)
+// log.Fatal(http.ListenAndServe(addr, r.middleware))
+// }
-func (r *Server) ServeHTTP(w go_http.ResponseWriter, req *go_http.Request) {
- r.middleware.ServeHTTP(w, req)
-}
+// func (r *Server) ServeHTTP(w go_http.ResponseWriter, req *go_http.Request) {
+// r.middleware.ServeHTTP(w, req)
+// }
diff --git a/internal/http/server_test.go b/internal/http/server_test.go
index f24c007..bbdb381 100755
--- a/internal/http/server_test.go
+++ b/internal/http/server_test.go
@@ -1,34 +1,34 @@
package http_test
-import (
- "os"
+// import (
+// "os"
- "github.com/codegangsta/negroni"
- "github.com/jchenry/jchenry/http"
- "github.com/jchenry/jchenry/rest"
-)
+// "github.com/codegangsta/negroni"
+// "github.com/jchenry/jchenry/http"
+// "github.com/jchenry/jchenry/rest"
+// )
-func ExampleServer() {
- type contact struct {
- ID int64 `json:"id"`
- First string `json:"firstName"`
- Last string `json:"lastName"`
- Email string `json:"emailAddress"`
- }
+// func ExampleServer() {
+// type contact struct {
+// ID int64 `json:"id"`
+// First string `json:"firstName"`
+// Last string `json:"lastName"`
+// Email string `json:"emailAddress"`
+// }
- s := http.NewServer(
- negroni.Classic(),
- http.NewJulienschmidtHTTPRouter()).
- Service("",
- rest.Collection(new(contact),
- nil,
- ),
- )
+// s := http.NewServer(
+// negroni.Classic(),
+// http.NewJulienschmidtHTTPRouter()).
+// Service("",
+// rest.Collection(new(contact),
+// nil,
+// ),
+// )
- port := os.Getenv("PORT")
- if port == "" {
- port = "8080"
- }
+// port := os.Getenv("PORT")
+// if port == "" {
+// port = "8080"
+// }
- s.Run(":" + port)
-}
+// s.Run(":" + port)
+// }
diff --git a/internal/http/service.go b/internal/http/service.go
index bf0f23c..9adb4d8 100644
--- a/internal/http/service.go
+++ b/internal/http/service.go
@@ -26,3 +26,13 @@ package http
// MethodConnect = "CONNECT"
// MethodOptions = "OPTIONS"
// MethodTrace = "TRACE"
+
+type Service interface {
+ Register(m *Mux) error
+}
+
+type ServiceFunc func(m *Mux) error
+
+func (s ServiceFunc) Register(m *Mux) error {
+ return s(m)
+}
diff --git a/internal/payments/config.go b/internal/payments/config.go
index 23df01c..15875d1 100755
--- a/internal/payments/config.go
+++ b/internal/payments/config.go
@@ -1,25 +1,25 @@
package payments
-import (
- "fmt"
- "os"
-)
+// import (
+// "fmt"
+// "os"
+// )
-type Config struct {
- StripeKey string
- StripeProductID string
- RedirectURL string
- TenantSetup func(subscriptionID, customerID string) (tenantID string)
-}
+// type Config struct {
+// StripeKey string
+// StripeProductID string
+// RedirectURL string
+// TenantSetup func(subscriptionID, customerID string) (tenantID string)
+// }
-func FromEnv() Config {
- return Config{
- StripeKey: os.Getenv("STRIPE_KEY"),
- StripeProductID: os.Getenv("STRIPE_PRODUCT_ID"),
- RedirectURL: "/",
- }
-}
+// func FromEnv() Config {
+// return Config{
+// StripeKey: os.Getenv("STRIPE_KEY"),
+// StripeProductID: os.Getenv("STRIPE_PRODUCT_ID"),
+// RedirectURL: "/",
+// }
+// }
-func PrintConfig() {
- fmt.Printf("%#v\n", FromEnv())
-}
+// func PrintConfig() {
+// fmt.Printf("%#v\n", FromEnv())
+// }
diff --git a/internal/payments/middleware.go b/internal/payments/middleware.go
index 64a26d5..6c4d407 100755
--- a/internal/payments/middleware.go
+++ b/internal/payments/middleware.go
@@ -1,27 +1,26 @@
package payments
-import (
- "net/http"
+// import (
+// "net/http"
- "github.com/jchenry/jchenry/internal/auth"
-)
+// "github.com/jchenry/x/internal/auth"
+// )
-func HasTenantAndSubscription(productID string) func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
- return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+// func HasTenantAndSubscription(productID string) func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+// return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+// session, err := auth.Store.Get(r, auth.SessionName)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- session, err := auth.Store.Get(r, auth.SessionName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- if u, ok := session.Values["profile"]; ok {
- user := u.(auth.User)
- if _, exist := user.Apps[productID]; exist {
- next(w, r)
- } else {
- http.Redirect(w, r, "/subscription", http.StatusSeeOther)
- }
- }
- }
-}
+// if u, ok := session.Values["profile"]; ok {
+// user := u.(auth.User)
+// if _, exist := user.Apps[productID]; exist {
+// next(w, r)
+// } else {
+// http.Redirect(w, r, "/subscription", http.StatusSeeOther)
+// }
+// }
+// }
+// }
diff --git a/internal/payments/service.go b/internal/payments/service.go
index abd1895..f89ea35 100755
--- a/internal/payments/service.go
+++ b/internal/payments/service.go
@@ -1,121 +1,121 @@
package payments
-import (
- "fmt"
- "net/http"
+// import (
+// "fmt"
+// "net/http"
- "github.com/codegangsta/negroni"
- "github.com/jchenry/jchenry/internal/auth"
- _http "github.com/jchenry/jchenry/internal/http"
- "github.com/stripe/stripe-go"
- "github.com/stripe/stripe-go/client"
- "github.com/stripe/stripe-go/customer"
- "github.com/stripe/stripe-go/plan"
- "github.com/stripe/stripe-go/product"
- "github.com/stripe/stripe-go/sub"
-)
+// "github.com/codegangsta/negroni"
+// "github.com/jchenry/x/internal/auth"
+// _http "github.com/jchenry/x/internal/http"
+// "github.com/stripe/stripe-go"
+// "github.com/stripe/stripe-go/client"
+// "github.com/stripe/stripe-go/customer"
+// "github.com/stripe/stripe-go/plan"
+// "github.com/stripe/stripe-go/product"
+// "github.com/stripe/stripe-go/sub"
+// )
-func Service(c Config, auth *auth.ServiceInstance) ServiceInstance {
- stripe.Key = c.StripeKey
- sc := &client.API{}
- sc.Init(c.StripeKey, nil)
- return ServiceInstance{
- c: c,
- stripe: sc,
- auth: auth,
- }
-}
+// func Service(c Config, auth *auth.ServiceInstance) ServiceInstance {
+// stripe.Key = c.StripeKey
+// sc := &client.API{}
+// sc.Init(c.StripeKey, nil)
+// return ServiceInstance{
+// c: c,
+// stripe: sc,
+// auth: auth,
+// }
+// }
-type ServiceInstance struct {
- c Config
- stripe *client.API
- auth *auth.ServiceInstance
-}
+// type ServiceInstance struct {
+// c Config
+// stripe *client.API
+// auth *auth.ServiceInstance
+// }
-func (si ServiceInstance) Register(uriBase string, s *_http.Server) {
- s.Get(uriBase+"/subscription", "subscription info endpoint", negroni.New(
- negroni.HandlerFunc(auth.IsAuthenticated),
- negroni.Wrap(http.HandlerFunc(si.subscriptionHandler)),
- )).Post(uriBase+"/subscription", "subscription payment endpoint", negroni.New(
- negroni.HandlerFunc(auth.IsAuthenticated),
- negroni.Wrap(http.HandlerFunc(si.paymentHandler)),
- ))
+// func (si ServiceInstance) Register(uriBase string, s *_http.Server) {
+// s.Get(uriBase+"/subscription", "subscription info endpoint", negroni.New(
+// negroni.HandlerFunc(auth.IsAuthenticated),
+// negroni.Wrap(http.HandlerFunc(si.subscriptionHandler)),
+// )).Post(uriBase+"/subscription", "subscription payment endpoint", negroni.New(
+// negroni.HandlerFunc(auth.IsAuthenticated),
+// negroni.Wrap(http.HandlerFunc(si.paymentHandler)),
+// ))
-}
+// }
-func (si ServiceInstance) subscriptionHandler(w http.ResponseWriter, r *http.Request) {
+// func (si ServiceInstance) subscriptionHandler(w http.ResponseWriter, r *http.Request) {
- prod, _ := product.Get(si.c.StripeProductID, nil)
+// prod, _ := product.Get(si.c.StripeProductID, nil)
- params := &stripe.PlanListParams{
- Product: &si.c.StripeProductID,
- }
+// params := &stripe.PlanListParams{
+// Product: &si.c.StripeProductID,
+// }
- it := plan.List(params)
- var plans []stripe.Plan
- for it.Next() {
- plans = append(plans, *it.Plan())
- }
- _http.RenderTemplate(w, "subscription", offering{Product: *prod, Plans: plans})
-}
+// it := plan.List(params)
+// var plans []stripe.Plan
+// for it.Next() {
+// plans = append(plans, *it.Plan())
+// }
+// _http.RenderTemplate(w, "subscription", offering{Product: *prod, Plans: plans})
+// }
-type offering struct {
- Product stripe.Product
- Plans []stripe.Plan
-}
+// type offering struct {
+// Product stripe.Product
+// Plans []stripe.Plan
+// }
-func (si ServiceInstance) paymentHandler(w http.ResponseWriter, r *http.Request) {
+// func (si ServiceInstance) paymentHandler(w http.ResponseWriter, r *http.Request) {
- session, err := auth.Store.Get(r, auth.SessionName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// session, err := auth.Store.Get(r, auth.SessionName)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- if u, ok := session.Values["profile"]; ok {
- user := u.(auth.User)
- r.ParseForm()
+// if u, ok := session.Values["profile"]; ok {
+// user := u.(auth.User)
+// r.ParseForm()
- params := &stripe.CustomerParams{
- Email: stripe.String(user.Email),
- Name: stripe.String(fmt.Sprintf("%s, %s", user.LastName, user.FirstName)),
- }
- params.SetSource(r.PostFormValue("stripeToken"))
- cus, err := customer.New(params)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// params := &stripe.CustomerParams{
+// Email: stripe.String(user.Email),
+// Name: stripe.String(fmt.Sprintf("%s, %s", user.LastName, user.FirstName)),
+// }
+// params.SetSource(r.PostFormValue("stripeToken"))
+// cus, err := customer.New(params)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- p := &stripe.SubscriptionParams{
- Customer: stripe.String(cus.ID),
- Items: []*stripe.SubscriptionItemsParams{
- {
- Plan: stripe.String(r.PostFormValue("plan")),
- },
- },
- }
- s, err := sub.New(p)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// p := &stripe.SubscriptionParams{
+// Customer: stripe.String(cus.ID),
+// Items: []*stripe.SubscriptionItemsParams{
+// {
+// Plan: stripe.String(r.PostFormValue("plan")),
+// },
+// },
+// }
+// s, err := sub.New(p)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- if si.c.TenantSetup == nil {
- panic("need code to setup the tenant")
- }
+// if si.c.TenantSetup == nil {
+// panic("need code to setup the tenant")
+// }
- if user.Apps == nil {
- user.Apps = map[string]interface{}{}
- }
- user.Apps[si.c.StripeProductID] = si.c.TenantSetup(s.ID, user.ID)
- err = si.auth.UpdateUser(user)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+// if user.Apps == nil {
+// user.Apps = map[string]interface{}{}
+// }
+// user.Apps[si.c.StripeProductID] = si.c.TenantSetup(s.ID, user.ID)
+// err = si.auth.UpdateUser(user)
+// if err != nil {
+// http.Error(w, err.Error(), http.StatusInternalServerError)
+// return
+// }
- http.Redirect(w, r, si.c.RedirectURL, http.StatusSeeOther)
+// http.Redirect(w, r, si.c.RedirectURL, http.StatusSeeOther)
- }
-}
+// }
+// }
diff --git a/internal/rest/collection.go b/internal/rest/collection.go
deleted file mode 100755
index 1ef83dd..0000000
--- a/internal/rest/collection.go
+++ /dev/null
@@ -1,204 +0,0 @@
-package rest
-
-import (
- "fmt"
- "net/http"
- "reflect"
- "strconv"
- "strings"
-
- _http "github.com/jchenry/jchenry/internal/http"
-)
-
-const (
- //IDPathParameter represents the entity's id in the parameter map IDPathParameter = "id"
- IDPathParameter = "id"
-)
-
-// Collection - A Restful Collection interface backed by crud.CrudService
-type CollectionInstance struct {
- basePath string
- name string
- instanceType reflect.Type
- service CollectionStore
-}
-
-type CollectionStore interface {
- // Find returns a pointer to an array of the results found based on params
- // or an error
- Find(entityArrPtr interface{}, params map[string]interface{}) error
- // Create returns the identifier for the newly accepted entity, or error
- Create(entityPtr interface{}) error
- // Update returns the id of the newly updated entity, or error
- Update(entityPtr interface{}) error
- // Delete returns whether the entity, specified by id, was successfully deleted
- // or error
- Delete(entityPtr interface{}) error
-}
-
-// type GetIDPathParameter func(*http.Request)
-
-// Collection - Create a new instance of RESTCollection
-func Collection(entityPtr interface{}, service CollectionStore) *CollectionInstance {
- t := reflect.TypeOf(entityPtr).Elem()
- return &CollectionInstance{
- name: strings.ToLower(t.Name()),
- instanceType: t,
- service: service,
- }
-}
-
-func (collection *CollectionInstance) Register(uriBase string, restServer *_http.Server) {
- plural := properPlural(collection.name)
-
- urlBase := uriBase + "/" + plural //collection.name + "s"
- restServer.
- Post(urlBase, "create a "+collection.name, http.HandlerFunc(collection.create)).
- Put(urlBase+"/:"+IDPathParameter, "update a "+collection.name, http.HandlerFunc(collection.update)).
- Delete(urlBase+"/:"+IDPathParameter, "delete a "+collection.name, http.HandlerFunc(collection.remove)).
- Get(urlBase+"/:"+IDPathParameter, "get a "+collection.name+" by id", http.HandlerFunc(collection.find)).
- Get(urlBase, "get "+collection.name+"s", http.HandlerFunc(collection.find))
-}
-
-func properPlural(word string) string {
- if strings.HasSuffix(word, "s") {
- return word
- } else if strings.HasSuffix(word, "y") {
- return word[:len(word)-1] + "ies"
- } else {
- return word + "s"
- }
-}
-
-func (collection *CollectionInstance) create(response http.ResponseWriter, request *http.Request) {
- entityPtr := reflect.New(collection.instanceType).Interface() //collection.instanceProviderPtr.NewInstance()
-
- err := _http.ReadEntity(request, entityPtr)
- if err != nil {
- _http.WriteErrorResponse(response, http.StatusBadRequest, err.Error())
- return
- }
-
- err = collection.service.Create(entityPtr)
- if err != nil {
- _http.WriteErrorResponse(response, http.StatusInternalServerError, err.Error())
- return
- }
-
- response.WriteHeader(http.StatusCreated)
- _http.WriteEntity(response, entityPtr)
-}
-
-func (collection *CollectionInstance) update(response http.ResponseWriter, request *http.Request) {
- entityPtr := reflect.New(collection.instanceType).Interface() //collection.instanceProviderPtr.NewInstance()
- err := _http.ReadEntity(request, entityPtr)
-
- if err != nil {
- _http.WriteErrorResponse(response, http.StatusBadRequest, err.Error())
- return
- }
- id := request.Form.Get(IDPathParameter)
- err = collection.service.Find(&[]interface{}{}, map[string]interface{}{IDPathParameter: id})
-
- if err != nil {
- if err == _http.ErrNotFound {
- _http.WriteErrorResponse(response, http.StatusNotFound, fmt.Sprintf("%v with id %v not found", collection.name, id))
- } else {
- _http.WriteErrorResponse(response, http.StatusInternalServerError, err.Error())
- }
- return
- }
- err = collection.service.Update(entityPtr)
- if err != nil {
- _http.WriteErrorResponse(response, http.StatusInternalServerError, err.Error())
- return
- }
-
- response.WriteHeader(http.StatusOK)
- _http.WriteEntity(response, entityPtr)
-}
-
-func (collection *CollectionInstance) remove(response http.ResponseWriter, request *http.Request) {
- id := request.Form.Get(IDPathParameter)
- err := collection.service.Find(&[]interface{}{}, map[string]interface{}{IDPathParameter: id})
- if err != nil {
- if err == _http.ErrNotFound {
- _http.WriteErrorResponse(response, http.StatusNotFound, fmt.Sprintf("%v with id %v not found", collection.name, id))
- } else {
- _http.WriteErrorResponse(response, http.StatusInternalServerError, err.Error())
- }
- return
- }
- entityPtr := reflect.New(collection.instanceType).Interface() //collection.instanceProviderPtr.NewInstance()
- field := reflect.Indirect(reflect.ValueOf(entityPtr)).FieldByName(strings.ToUpper(IDPathParameter))
- if !field.CanSet() {
- _http.WriteErrorResponse(response, http.StatusInternalServerError, "entity does not have "+IDPathParameter+" field or field is not setable")
- }
- parsedID, err := strconv.ParseInt(id, 0, 64)
- if err != nil {
- _http.WriteErrorResponse(response, http.StatusInternalServerError, err.Error())
-
- }
- field.SetInt(parsedID)
-
- err = collection.service.Delete(entityPtr)
- if err != nil {
- _http.WriteErrorResponse(response, http.StatusInternalServerError, err.Error())
- return
- }
-
- response.WriteHeader(http.StatusNoContent)
-}
-
-func (collection *CollectionInstance) find(response http.ResponseWriter, request *http.Request) {
- id := request.Form.Get(IDPathParameter)
- arrv := reflect.New(reflect.SliceOf(reflect.PtrTo(collection.instanceType)))
- arri := arrv.Interface()
- err := collection.service.Find(arri, valuesToMap(request.URL.Query(), id))
-
- if err != nil {
- if err == _http.ErrNotFound {
- _http.WriteErrorResponse(response, http.StatusNotFound, fmt.Sprintf("%v with id %v not found", collection.name, id))
- } else {
- _http.WriteErrorResponse(response, http.StatusInternalServerError, err.Error())
- }
- return
- }
-
- var results interface{}
-
- if reflect.Indirect(arrv).Len() == 1 {
- results = reflect.Indirect(arrv).Index(0).Interface()
- fmt.Println(results)
- } else {
- results = &ResultSetResponse{
- Metadata: Metadata{
- ResultSet: ResultSetMetadata{
- Count: reflect.Indirect(arrv).Len(),
- //TODO: need to accomidate limit and offset here.
- },
- },
- Results: arri,
- }
- }
-
- response.WriteHeader(http.StatusOK)
- _http.WriteEntity(response, results)
-}
-
-func valuesToMap(params map[string][]string, id string) map[string]interface{} {
- m := make(map[string]interface{})
- for key, val := range params {
- if len(val) == 1 {
- m[key] = val[0]
- } else {
- m[key] = val
- }
- }
-
- if id != "" {
- m[IDPathParameter] = id
- }
-
- return m
-}
diff --git a/internal/rest/collection_test.go b/internal/rest/collection_test.go
deleted file mode 100755
index ec712de..0000000
--- a/internal/rest/collection_test.go
+++ /dev/null
@@ -1,294 +0,0 @@
-package rest_test
-
-// import (
-// "encoding/json"
-// "fmt"
-// "io/ioutil"
-// "log"
-// "net/http"
-// "net/http/httptest"
-// "path/filepath"
-// "reflect"
-// "runtime"
-// "strings"
-// "testing"
-
-// // "github.com/jchenry/crud"
-// keel_http "github.com/jchenry/http"
-// keel_httptest "github.com/jchenry/http/httptest"
-// // "github.com/jchenry/rest"
-// )
-
-// type TestObject struct {
-// ID int64 `json:"id"`
-// Name string `json:"name"`
-// }
-
-// var service *crud.InMemoryCrudService
-// var instanceType reflect.Type = reflect.TypeOf(TestObject{})
-
-// func Setup() {
-// if service == nil {
-// service = crud.NewInMemoryCrudService()
-// }
-// log.SetOutput(ioutil.Discard)
-
-// }
-
-// // func TestRESTCollectionTestSuite(t *testing.T) {
-// // rsuite := new(RESTCollectionTestSuite)
-// // rservice = db.NewInMemoryCrudService()
-// // rinstanceType = reflect.TypeOf(TestObject{})
-// // log.SetOutput(ioutil.Discard)
-// // Run(t, rsuite)
-// // }
-
-// func TestCollectionCreate(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-
-// container := createCollectionContainer(instanceType, service)
-
-// requestJSON, err := json.Marshal(TestObject{Name: "Foo"})
-// if err != nil {
-// Fail(t, "unable to json body")
-// }
-
-// request, err := http.NewRequest("POST", "/testobjects", strings.NewReader(string(requestJSON)))
-// request.Header.Add("Content-Type", keel_http.MimeJSON)
-// if err != nil {
-// Fail(t, "unable to create request")
-// }
-// response := httptest.NewRecorder()
-
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 201, "{\n \"id\": 1,\n \"name\": \"Foo\"\n }")
-// }
-
-// func TestCollectionCreateBadRequest(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-
-// container := createCollectionContainer(instanceType, service)
-
-// request, err := http.NewRequest("POST", "/testobjects", strings.NewReader(string("{malformedjson}")))
-// request.Header.Add("Content-Type", keel_http.MimeJSON)
-// if err != nil {
-// Fail(t, "unable to create request")
-// }
-// response := httptest.NewRecorder()
-
-// container.ServeHTTP(response, request)
-
-// keel_httptest.ValidateResponse(t, response, 400, "{\n \"Status\": 400,\n \"DeveloperMessage\": \"invalid character 'm' looking for beginning of object key string\"\n }")
-// }
-
-// func TestCollectionCreateInternalError(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-
-// container := createCollectionContainer(instanceType, NewAllFailingCrudService())
-
-// requestJSON, err := json.Marshal(TestObject{Name: "Foo"})
-// if err != nil {
-// Fail(t, "unable to json body")
-// }
-// request, err := http.NewRequest("POST", "/testobjects", strings.NewReader(string(requestJSON)))
-// request.Header.Add("Content-Type", keel_http.MimeJSON)
-// if err != nil {
-// Fail(t, "unable to create request")
-// }
-// response := httptest.NewRecorder()
-
-// container.ServeHTTP(response, request)
-
-// keel_httptest.ValidateResponse(t, response, 500, "{\n \"Status\": 500,\n \"DeveloperMessage\": \"unable to create\"\n }")
-// }
-
-// func TestCollectionUpdate(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-// to.ID = 1
-
-// container := createCollectionContainer(instanceType, service)
-
-// requestJSON := keel_httptest.GetJSONReader(t, to)
-
-// request, response := keel_httptest.GetRequestAndResponse(t, "PUT", "/testobjects/1", requestJSON)
-
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 200, "{\n \"id\": 1,\n \"name\": \"foo\"\n }")
-
-// }
-
-// func TestCollectionUpdateBadRequest(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-// to.ID = 1
-
-// container := createCollectionContainer(instanceType, service)
-
-// request, response := keel_httptest.GetRequestAndResponse(t, "PUT", "/testobjects/1", strings.NewReader(string("{malformedjson}")))
-
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 400, "{\n \"Status\": 400,\n \"DeveloperMessage\": \"invalid character 'm' looking for beginning of object key string\"\n }")
-// }
-
-// func TestCollectionUpdateBadEntityID(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-// to.ID = 42
-
-// container := createCollectionContainer(instanceType, service)
-// requestJSON := keel_httptest.GetJSONReader(t, to)
-
-// request, response := keel_httptest.GetRequestAndResponse(t, "PUT", "/testobjects/42", requestJSON)
-
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 404, "{\n \"Status\": 404,\n \"DeveloperMessage\": \"testobject with id 42 not found\"\n }")
-// }
-
-// func TestCollectionUpdateInternalErrorOnFind(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-// to.ID = 1
-
-// container := createCollectionContainer(instanceType, NewAllFailingCrudService())
-// requestJSON := keel_httptest.GetJSONReader(t, to)
-// request, response := keel_httptest.GetRequestAndResponse(t, "PUT", "/testobjects/1", requestJSON)
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 500, "{\n \"Status\": 500,\n \"DeveloperMessage\": \"unable to find\"\n }")
-// }
-
-// func TestCollectionUpdateInternalErrorOnServiceUpdate(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-// to.ID = 1
-
-// container := createCollectionContainer(instanceType, NewFailingCrudService(service, false, false, true, false))
-// requestJSON := keel_httptest.GetJSONReader(t, to)
-// request, response := keel_httptest.GetRequestAndResponse(t, "PUT", "/testobjects/1", requestJSON)
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 500, "{\n \"Status\": 500,\n \"DeveloperMessage\": \"unable to update\"\n }")
-// }
-
-// func TestDelete(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "deleteObject"
-
-// _, err := service.Create(to)
-// if err != nil {
-// Fail(t, "unable to create deleteObject")
-// }
-
-// container := createCollectionContainer(instanceType, service)
-// uri := fmt.Sprintf("/testobjects/%d", int(to.ID))
-// request, response := keel_httptest.GetRequestAndResponse(t, "DELETE", uri, nil)
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 204, "")
-
-// request, response = keel_httptest.GetRequestAndResponse(t, "DELETE", uri, nil)
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 404, "{\n \"Status\": 404,\n \"DeveloperMessage\": \"testobject with id 2 not found\"\n }")
-
-// }
-
-// func TestCollectionDeleteInternalErrorOnFind(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-// to.ID = 1
-
-// container := createCollectionContainer(instanceType, NewAllFailingCrudService())
-// requestJSON := keel_httptest.GetJSONReader(t, to)
-// request, response := keel_httptest.GetRequestAndResponse(t, "DELETE", "/testobjects/1", requestJSON)
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 500, "{\n \"Status\": 500,\n \"DeveloperMessage\": \"unable to find\"\n }")
-// }
-
-// func TestCollectionDeleteInternalErrorOnServiceDelete(t *testing.T) {
-// Setup()
-// to := new(TestObject)
-// to.Name = "foo"
-// to.ID = 1
-
-// container := createCollectionContainer(instanceType, NewFailingCrudService(service, false, false, false, true))
-// requestJSON := keel_httptest.GetJSONReader(t, to)
-// request, response := keel_httptest.GetRequestAndResponse(t, "DELETE", "/testobjects/1", requestJSON)
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 500, "{\n \"Status\": 500,\n \"DeveloperMessage\": \"unable to delete\"\n }")
-// }
-
-// func TestCollectionFindSingleItem(t *testing.T) {
-// Setup()
-// container := createCollectionContainer(instanceType, service)
-// uri := fmt.Sprintf("/testobjects/%d", 1)
-// request, response := keel_httptest.GetRequestAndResponse(t, "GET", uri, nil)
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 200, "{\n \"id\": 1,\n \"name\": \"foo\"\n }")
-
-// }
-
-// //TODO we really should support thie in InMemoryCrudService for code coverage purposes
-// // func TestFindOnQuery(t *testing.T) {
-// // container := createCollectionContainer(TestObject{}, service)
-// // uri := "/testobjects?name=foo"
-// // request, response := keel_httptest.GetRequestAndResponse(t, "GET", uri, nil)
-// // container.ServeHTTP(response, request)
-// // keel_httptest.ValidateResponse(t, response, 200, "{\n \"id\": 1,\n \"name\": \"Foo\"\n }")
-// //
-// // }
-
-// func TestCollectionFindInternalFailure(t *testing.T) {
-// Setup()
-// container := createCollectionContainer(instanceType, NewFailingCrudService(service, false, true, false, false))
-// uri := fmt.Sprintf("/testobjects/%d", 1)
-// request, response := keel_httptest.GetRequestAndResponse(t, "GET", uri, nil)
-// container.ServeHTTP(response, request)
-// keel_httptest.ValidateResponse(t, response, 500, "{\n \"Status\": 500,\n \"DeveloperMessage\": \"unable to find\"\n }")
-// }
-
-// func createCollectionContainer(entity reflect.Type, service crud.CrudService) *rest.Server {
-// s := rest.NewServer().
-// Service("", rest.NewCollection(entity, service))
-// return s
-// }
-
-// func Fail(tb testing.TB, msg string) {
-// Assert(tb, false, msg)
-// }
-
-// // Assert fails the test if the condition is false.
-// func Assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
-// if !condition {
-// _, file, line, _ := runtime.Caller(1)
-// fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
-// tb.FailNow()
-// }
-// }
-
-// func NewAllFailingCrudService() crud.CrudService {
-// return failingCrudService{}
-// }
-
-// type failingCrudService struct{}
-
-// func (a *failingCrudService) Find(entityArrPtr interface{}, params map[string]interface{}) (err error) {
-// return crud.ErrNotFound
-// }
-// func (a *failingCrudService) Create(entityPtr interface{}) (id interface{}, err error) {
-// return nil, crud.ErrBadIDType
-// }
-// func (a *failingCrudService) Update(entityPtr interface{}) (id interface{}, err error) {
-// return nil, crud.ErrNotFound
-// }
-// func (a *failingCrudService) Delete(entityPtr interface{}) error { return crud.ErrNotFound }
diff --git a/internal/rest/resultset_response.go b/internal/rest/resultset_response.go
deleted file mode 100755
index ab60ef2..0000000
--- a/internal/rest/resultset_response.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package rest
-
-//ResultSetMetadata -
-type ResultSetMetadata struct {
- Count int `json:"count"`
- Offset int `json:"offset"`
- Limit int `json:"limit"`
-}
-
-//Metadata -
-type Metadata struct {
- ResultSet ResultSetMetadata `json:"resultset"`
-}
-
-//ResultSetResponse -
-type ResultSetResponse struct {
- Metadata Metadata `json:"metadata"`
- Results interface{} `json:"results"`
-}
diff --git a/internal/rss/model.go b/internal/rss/model.go
new file mode 100644
index 0000000..72c8e25
--- /dev/null
+++ b/internal/rss/model.go
@@ -0,0 +1,118 @@
+package rss
+
+import (
+ "encoding/json"
+ "time"
+)
+
+// Feed is an RSS Feed
+type Feed struct {
+ Title string `json:"title,omitempty"`
+ Link string `json:"link,omitempty"`
+ Description string `json:"description,omitempty"`
+ Language string `json:"language,omitempty"`
+ Copyright string `json:"copyright,omitempty"`
+ ManagingEditor string `json:"managingEditor,omitempty"`
+ WebMaster string `json:"webMaster,omitempty"`
+ PubDate string `json:"pubDate,omitempty"`
+ PubDateParsed *time.Time `json:"pubDateParsed,omitempty"`
+ LastBuildDate string `json:"lastBuildDate,omitempty"`
+ LastBuildDateParsed *time.Time `json:"lastBuildDateParsed,omitempty"`
+ Categories []*Category `json:"categories,omitempty"`
+ Generator string `json:"generator,omitempty"`
+ Docs string `json:"docs,omitempty"`
+ TTL string `json:"ttl,omitempty"`
+ Image *Image `json:"image,omitempty"`
+ Rating string `json:"rating,omitempty"`
+ SkipHours []string `json:"skipHours,omitempty"`
+ SkipDays []string `json:"skipDays,omitempty"`
+ Cloud *Cloud `json:"cloud,omitempty"`
+ TextInput *TextInput `json:"textInput,omitempty"`
+ // DublinCoreExt *ext.DublinCoreExtension `json:"dcExt,omitempty"`
+ // ITunesExt *ext.ITunesFeedExtension `json:"itunesExt,omitempty"`
+ // Extensions ext.Extensions `json:"extensions,omitempty"`
+ Items []*Item `json:"items"`
+ Version string `json:"version"`
+}
+
+func (f Feed) String() string {
+ json, _ := json.MarshalIndent(f, "", " ")
+ return string(json)
+}
+
+// Item is an RSS Item
+type Item struct {
+ Title string `json:"title,omitempty"`
+ Link string `json:"link,omitempty"`
+ Description string `json:"description,omitempty"`
+ Content string `json:"content,omitempty"`
+ Author string `json:"author,omitempty"`
+ Categories []*Category `json:"categories,omitempty"`
+ Comments string `json:"comments,omitempty"`
+ Enclosure *Enclosure `json:"enclosure,omitempty"`
+ GUID *GUID `json:"guid,omitempty"`
+ PubDate string `json:"pubDate,omitempty"`
+ PubDateParsed *time.Time `json:"pubDateParsed,omitempty"`
+ Source *Source `json:"source,omitempty"`
+ // DublinCoreExt *ext.DublinCoreExtension `json:"dcExt,omitempty"`
+ // ITunesExt *ext.ITunesItemExtension `json:"itunesExt,omitempty"`
+ // Extensions ext.Extensions `json:"extensions,omitempty"`
+}
+
+// Image is an image that represents the feed
+type Image struct {
+ URL string `json:"url,omitempty"`
+ Link string `json:"link,omitempty"`
+ Title string `json:"title,omitempty"`
+ Width string `json:"width,omitempty"`
+ Height string `json:"height,omitempty"`
+ Description string `json:"description,omitempty"`
+}
+
+// Enclosure is a media object that is attached to
+// the item
+type Enclosure struct {
+ URL string `json:"url,omitempty"`
+ Length string `json:"length,omitempty"`
+ Type string `json:"type,omitempty"`
+}
+
+// GUID is a unique identifier for an item
+type GUID struct {
+ Value string `json:"value,omitempty"`
+ IsPermalink string `json:"isPermalink,omitempty"`
+}
+
+// Source contains feed information for another
+// feed if a given item came from that feed
+type Source struct {
+ Title string `json:"title,omitempty"`
+ URL string `json:"url,omitempty"`
+}
+
+// Category is category metadata for Feeds and Entries
+type Category struct {
+ Domain string `json:"domain,omitempty"`
+ Value string `json:"value,omitempty"`
+}
+
+// TextInput specifies a text input box that
+// can be displayed with the channel
+type TextInput struct {
+ Title string `json:"title,omitempty"`
+ Description string `json:"description,omitempty"`
+ Name string `json:"name,omitempty"`
+ Link string `json:"link,omitempty"`
+}
+
+// Cloud allows processes to register with a
+// cloud to be notified of updates to the channel,
+// implementing a lightweight publish-subscribe protocol
+// for RSS feeds
+type Cloud struct {
+ Domain string `json:"domain,omitempty"`
+ Port string `json:"port,omitempty"`
+ Path string `json:"path,omitempty"`
+ RegisterProcedure string `json:"registerProcedure,omitempty"`
+ Protocol string `json:"protocol,omitempty"`
+}
diff --git a/internal/rss/parser.go b/internal/rss/parser.go
new file mode 100644
index 0000000..a5a98b9
--- /dev/null
+++ b/internal/rss/parser.go
@@ -0,0 +1,21 @@
+package rss
+
+import (
+ "io"
+
+ "golang.org/x/net/html"
+)
+
+func Parse(r io.Reader) *Feed {
+
+ // z := html.NewTokenizer(r)
+
+ return nil
+}
+
+func parseFeed(z html.Tokenizer) *Feed {
+ z.Next()
+ return nil
+}
+
+func parseVersion(z html.Tokenizer) {}
diff --git a/pkg/http/auth.go b/net/http/auth.go
similarity index 100%
rename from pkg/http/auth.go
rename to net/http/auth.go
diff --git a/pkg/http/multihandler.go b/net/http/multihandler.go
similarity index 99%
rename from pkg/http/multihandler.go
rename to net/http/multihandler.go
index b859ab9..bb5d8f8 100644
--- a/pkg/http/multihandler.go
+++ b/net/http/multihandler.go
@@ -32,6 +32,5 @@ func MutliHandler(h map[string]http.Handler) (http.HandlerFunc, error) {
} else {
NotFoundHandler.ServeHTTP(w, r)
}
-
}, nil
}
diff --git a/pkg/http/status_handler.go b/net/http/status_handler.go
similarity index 100%
rename from pkg/http/status_handler.go
rename to net/http/status_handler.go
diff --git a/rest/collection.go b/rest/collection.go
new file mode 100755
index 0000000..94426bb
--- /dev/null
+++ b/rest/collection.go
@@ -0,0 +1,107 @@
+package rest
+
+import (
+ "net/http"
+ "net/url"
+ "path/filepath"
+ "sync"
+
+ "github.com/jchenry/x/encoding"
+)
+
+type CollectionStore interface {
+ All(params url.Values) (interface{}, error)
+ Get(id string) (interface{}, error)
+ Delete(id string) error
+ Update(e interface{}) error
+ New(e interface{}) error
+}
+
+// Example: Collection(p, c, JSONEncoder, json.Decode(func()interface{}{return &foo{}}))
+
+// type Decoder func(io.Reader) (interface{}, error)
+
+func Collection(pool *sync.Pool, store CollectionStore, encode EntityEncoder, decode encoding.Decoder) http.HandlerFunc {
+ return EntityHandler(
+ collectionGet(store, encode),
+ collectionPost(store, encode, decode, pool),
+ collectionPut(store, encode, decode, pool),
+ collectionDelete(store, encode),
+ )
+}
+
+func collectionGet(store CollectionStore, encode EntityEncoder) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) { // GET
+ if id := filepath.Base(r.URL.Path); id != "" {
+ if e, err := store.Get(id); err == nil { // handle individual entity
+ encode(w, e)
+ } else {
+ w.WriteHeader(http.StatusInternalServerError)
+ encode(w, err)
+ }
+ } else {
+ if params, err := url.ParseQuery(r.URL.RawQuery); err == nil {
+ if e, err := store.All(params); err == nil { // handle all entities
+ encode(w, e)
+ } else {
+ // TODO: we really should write a header here, but need to figure out what it should be
+ w.WriteHeader(http.StatusInternalServerError)
+ }
+ } else {
+ // encode(w, err)
+ w.WriteHeader(http.StatusBadRequest)
+
+ }
+ }
+ }
+}
+
+func collectionPost(store CollectionStore, encode EntityEncoder, decode encoding.Decoder, pool *sync.Pool) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) { // POST TODO
+ e := pool.New()
+ defer pool.Put(e)
+ if err := decode(r.Body, e); err == nil {
+ if err = store.New(e); err == nil {
+ w.WriteHeader(http.StatusCreated)
+ } else {
+ w.WriteHeader(http.StatusInternalServerError)
+ }
+ } else {
+ w.WriteHeader(http.StatusBadRequest)
+ }
+ }
+}
+
+func collectionPut(store CollectionStore, encode EntityEncoder, decode encoding.Decoder, pool *sync.Pool) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) { // PUT TODO
+ e := pool.New()
+ defer pool.Put(e)
+ if err := decode(r.Body, e); err == nil {
+ if err = store.Update(e); err == nil {
+ w.WriteHeader(http.StatusAccepted)
+ encode(w, e)
+ } else {
+ w.WriteHeader(http.StatusInternalServerError)
+ encode(w, err)
+ }
+ } else {
+ w.WriteHeader(http.StatusBadRequest)
+ encode(w, err)
+
+ }
+ }
+}
+
+func collectionDelete(store CollectionStore, encode EntityEncoder) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) { // DELETE TODO
+ if id := filepath.Base(r.URL.Path); id != "" {
+ if err := store.Delete(id); err == nil {
+ w.WriteHeader(http.StatusNoContent)
+ } else {
+ w.WriteHeader(http.StatusInternalServerError)
+ }
+ } else {
+ w.WriteHeader(http.StatusBadRequest)
+ }
+ }
+}
diff --git a/rest/entity_handler.go b/rest/entity_handler.go
new file mode 100644
index 0000000..a96f1a4
--- /dev/null
+++ b/rest/entity_handler.go
@@ -0,0 +1,23 @@
+package rest
+
+import (
+ gohttp "net/http"
+
+ "github.com/jchenry/x/net/http"
+)
+
+// EntityHandler returns a handler that provides restful verbs, following a CRUD model
+func EntityHandler(
+ get gohttp.Handler,
+ post gohttp.Handler,
+ put gohttp.Handler,
+ delete gohttp.Handler,
+) gohttp.HandlerFunc {
+ h, _ := http.MutliHandler(map[string]gohttp.Handler{
+ gohttp.MethodGet: get,
+ gohttp.MethodPost: post,
+ gohttp.MethodPut: put,
+ gohttp.MethodDelete: delete,
+ })
+ return h
+}
diff --git a/rest/response_encoder.go b/rest/response_encoder.go
new file mode 100644
index 0000000..7a69b5d
--- /dev/null
+++ b/rest/response_encoder.go
@@ -0,0 +1,32 @@
+package rest
+
+import (
+ "net/http"
+
+ "github.com/jchenry/x/encoding"
+ "github.com/jchenry/x/encoding/json"
+ "github.com/jchenry/x/encoding/xml"
+)
+
+type EntityEncoder func(w http.ResponseWriter, e interface{})
+
+func JSONEncoder(w http.ResponseWriter, e interface{}) error {
+ return EntityResponseEncoder(w, "application/json", json.Encoder, e)
+}
+
+func XMLEncoder(w http.ResponseWriter, e interface{}) error {
+ return EntityResponseEncoder(w, "application/xml", xml.Encoder, e)
+}
+
+func EntityResponseEncoder(w http.ResponseWriter, contentType string, encoder encoding.Encoder, e interface{}) error {
+ w.Header().Set("content-type", contentType)
+ return encoder(w, e)
+}
+
+func ErrorResponseEncoder(w http.ResponseWriter, contentType string, encoder encoding.Encoder, status int, err error) error {
+ w.WriteHeader(status)
+ return EntityResponseEncoder(w, contentType, encoder, map[string]interface{}{
+ "status": status,
+ "message": err.Error,
+ })
+}
diff --git a/scripts/bin/openapigen.bash b/scripts/bin/openapigen.bash
deleted file mode 100755
index a4ea025..0000000
--- a/scripts/bin/openapigen.bash
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
- -i $1 \ #https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml \
- -g go \
- -o /local/out/go
\ No newline at end of file
diff --git a/scripts/bin/tel.bash b/scripts/bin/tel.bash
deleted file mode 100755
index 40d1246..0000000
--- a/scripts/bin/tel.bash
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-# A port of plan9 'tel' program
-
-for var in "$@"
-do
- if test -f "$HOME/.tel"; then
- grep -i $1 $HOME/.tel
- fi
-
- grep -hi $1 /usr/lib/tel /usr/lib/areacodes
-done
-
-exit
-
-
diff --git a/pkg/snowflake/README.md b/snowflake/README.md
similarity index 100%
rename from pkg/snowflake/README.md
rename to snowflake/README.md
diff --git a/pkg/snowflake/snowflake.go b/snowflake/snowflake.go
similarity index 100%
rename from pkg/snowflake/snowflake.go
rename to snowflake/snowflake.go
diff --git a/pkg/snowflake/snowflake_test.go b/snowflake/snowflake_test.go
similarity index 100%
rename from pkg/snowflake/snowflake_test.go
rename to snowflake/snowflake_test.go
diff --git a/pkg/arvelie/arvelie.go b/time/arvelie/arvelie.go
similarity index 100%
rename from pkg/arvelie/arvelie.go
rename to time/arvelie/arvelie.go
diff --git a/pkg/arvelie/arvelie_test.go b/time/arvelie/arvelie_test.go
similarity index 96%
rename from pkg/arvelie/arvelie_test.go
rename to time/arvelie/arvelie_test.go
index 166702c..7744519 100755
--- a/pkg/arvelie/arvelie_test.go
+++ b/time/arvelie/arvelie_test.go
@@ -6,7 +6,7 @@ import (
"testing"
"time"
- "github.com/jchenry/libs/arvelie"
+ "github.com/jchenry/x/time/arvelie"
)
func TestFromDate(t *testing.T) {
@@ -49,5 +49,4 @@ func TestToDate(t *testing.T) {
t.Fail()
}
}
-
}
diff --git a/pkg/arvelie/doc.go b/time/arvelie/doc.go
similarity index 100%
rename from pkg/arvelie/doc.go
rename to time/arvelie/doc.go
diff --git a/pkg/neralie/doc.go b/time/neralie/doc.go
similarity index 100%
rename from pkg/neralie/doc.go
rename to time/neralie/doc.go
diff --git a/pkg/neralie/neralie.go b/time/neralie/neralie.go
similarity index 100%
rename from pkg/neralie/neralie.go
rename to time/neralie/neralie.go
diff --git a/pkg/neralie/neralie_test.go b/time/neralie/neralie_test.go
similarity index 96%
rename from pkg/neralie/neralie_test.go
rename to time/neralie/neralie_test.go
index 200fa28..1c5d7eb 100755
--- a/pkg/neralie/neralie_test.go
+++ b/time/neralie/neralie_test.go
@@ -6,7 +6,7 @@ import (
"testing"
"time"
- "github.com/jchenry/libs/neralie"
+ "github.com/jchenry/x/time/neralie"
)
func TestFromTime(t *testing.T) {