summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhorus_arch2015-05-08 01:47:01 +0200
committerhorus_arch2015-05-08 01:47:01 +0200
commit57fd242908857312d304726d128cd8293c1b015a (patch)
tree9beddd9b758d27d3762833287c4e4ac9486f2b7f
parentfb7050acf2545c9d222d2c014460e4fcad5cc462 (diff)
downloadscribbled-57fd242908857312d304726d128cd8293c1b015a.tar.gz
Now with source files.
-rw-r--r--.gitignore1
-rw-r--r--scribbled/api.go107
-rw-r--r--scribbled/config.go83
-rw-r--r--scribbled/db.go14
-rw-r--r--scribbled/index.go41
-rw-r--r--scribbled/main.go77
-rw-r--r--scribbled/server.go70
-rw-r--r--scribbled/struct.go22
-rw-r--r--scribbled/util.go30
-rw-r--r--scribbled/view.go78
10 files changed, 522 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 100337f..2ce5875 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-scribbled
*.swp
*.db
db/
diff --git a/scribbled/api.go b/scribbled/api.go
new file mode 100644
index 0000000..308cb57
--- /dev/null
+++ b/scribbled/api.go
@@ -0,0 +1,107 @@
+package main
+
+import (
+ "encoding/json"
+ "log"
+ "net/http"
+)
+
+func ApiNewHandler(w http.ResponseWriter, r *http.Request) {
+ err := r.ParseForm()
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ note := Note{}
+ err = decoder.Decode(&note, r.PostForm)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ data, err := json.Marshal(note)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ err = Conf.DB.Put([]byte(note.Title), data, nil)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ Response(w, map[string]interface{}{"Title": note.Title, "Url": Conf.VirtualRoot + "/view/" + note.Title})
+}
+
+func ApiGetHandler(w http.ResponseWriter, r *http.Request) {
+ err := r.ParseForm()
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ note := Note{}
+ err = decoder.Decode(&note, r.Form)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ data, err := Conf.DB.Get([]byte(note.Title), nil)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, "Not Found", http.StatusNotFound)
+ return
+ }
+
+ err = json.Unmarshal(data, &note)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ Response(w, map[string]interface{}{"scribble": note, "Url": Conf.VirtualRoot + "/" + note.Title})
+ //log.Println(string(RenderMarkdown([]byte(note.Post))))
+}
+
+func SearchHandler(w http.ResponseWriter, r *http.Request) {
+ err := r.ParseForm()
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ note := Note{}
+ note.VirtualRoot = Conf.VirtualRoot
+
+ /*
+ val := r.URL.Query()
+ key := val["q"][0]
+ */
+ key := r.Form.Get("q")
+ _, err = Conf.DB.Get([]byte(key), nil)
+ http.Redirect(w, r, Conf.VirtualRoot+"/"+key, 301)
+ /*
+ if err != nil {
+ http.Redirect(w, r, Conf.VirtualRoot+"/"+key, 301)
+ note.NotFound = true
+ note.Title = key
+ err = ExecTemplate("index.html", w, r, note)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ }
+ return
+ }
+ http.Redirect(w, r, Conf.VirtualRoot+"/"+key, 301)
+ */
+}
diff --git a/scribbled/config.go b/scribbled/config.go
new file mode 100644
index 0000000..c6598b1
--- /dev/null
+++ b/scribbled/config.go
@@ -0,0 +1,83 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "strings"
+)
+
+func NewConfiguration(path string) *Configuration {
+ file, err := os.Open(path)
+ if err != nil {
+ log.Fatal("ERROR: Error opening config file. Please provide on with -config")
+ os.Exit(-1)
+ }
+
+ decoder := json.NewDecoder(file)
+ conf := &Configuration{}
+ err = decoder.Decode(conf)
+ if err != nil {
+ log.Fatal("ERROR: Error parsing config file.", err)
+ os.Exit(-1)
+ }
+
+ return conf
+}
+
+func (conf *Configuration) configInit() {
+ if !DirExists(conf.StaticDir) {
+ err := os.MkdirAll(conf.StaticDir, 0755)
+ if err != nil {
+ log.Fatal("ERROR: Can't create directory "+conf.StaticDir, err)
+ os.Exit(-1)
+ }
+ }
+ if !DirExists(conf.TemplateDir) {
+ err := os.MkdirAll(conf.TemplateDir, 0755)
+ if err != nil {
+ log.Fatal("ERROR: Can't create directory "+conf.TemplateDir, err)
+ os.Exit(-1)
+ }
+ }
+ if !DirExists(conf.DatabasePath) {
+ err := os.MkdirAll(conf.DatabasePath, 0755)
+ if err != nil {
+ log.Fatal("ERROR: Can't create directory "+conf.DatabasePath, err)
+ os.Exit(-1)
+ }
+ }
+ if !strings.HasPrefix(conf.VirtualRoot, "/") {
+ conf.VirtualRoot = "/" + conf.VirtualRoot
+ }
+ if strings.HasSuffix(conf.VirtualRoot, "/") {
+ conf.VirtualRoot = strings.TrimSuffix(conf.VirtualRoot, "/")
+ }
+}
+
+func GenConfig(path string) {
+ if path == "" {
+ path = "config.json"
+ }
+ Conf := Configuration{}
+ Conf.StaticDir = "static"
+ Conf.TemplateDir = "templates"
+ Conf.Ip = "127.0.0.1"
+ Conf.Port = 8765
+ Conf.VirtualRoot = "/"
+ Conf.DatabasePath = "db"
+
+ file, err := json.MarshalIndent(&Conf, "", " ")
+ if err != nil {
+ log.Fatal("ERROR: Error parsing json.", err)
+ }
+
+ err = ioutil.WriteFile(path, file, 0644)
+ if err != nil {
+ log.Fatal("ERROR: Writing file to "+path, err)
+ }
+
+ fmt.Println("INFO: Generated new config file (" + path + ").")
+}
diff --git a/scribbled/db.go b/scribbled/db.go
new file mode 100644
index 0000000..db4279f
--- /dev/null
+++ b/scribbled/db.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+ "github.com/syndtr/goleveldb/leveldb"
+ "log"
+)
+
+func (c *Configuration) NewDatabase() *leveldb.DB {
+ db, err := leveldb.OpenFile(c.DatabasePath, nil)
+ if err != nil {
+ log.Panic("ERROR: Error opening database. ", err)
+ }
+ return db
+}
diff --git a/scribbled/index.go b/scribbled/index.go
new file mode 100644
index 0000000..9e93720
--- /dev/null
+++ b/scribbled/index.go
@@ -0,0 +1,41 @@
+package main
+
+import (
+ "encoding/json"
+ "github.com/gorilla/mux"
+ "log"
+ "net/http"
+)
+
+func IndexHandler(w http.ResponseWriter, r *http.Request) {
+ err := ExecTemplate("index.html", w, r)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+func ScribbleHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+
+ note := Note{}
+ note.Title = vars["title"]
+ data, err := Conf.DB.Get([]byte(note.Title), nil)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ NotFoundHandler(w, r)
+ return
+ }
+
+ err = json.Unmarshal(data, &note)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ err = ExecTemplate("index.html", w, r, note)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
diff --git a/scribbled/main.go b/scribbled/main.go
new file mode 100644
index 0000000..bc6f347
--- /dev/null
+++ b/scribbled/main.go
@@ -0,0 +1,77 @@
+package main
+
+import (
+ "flag"
+ "github.com/gorilla/mux"
+ "github.com/gorilla/schema"
+ "github.com/gorilla/sessions"
+ "html/template"
+ "log"
+ "net/http"
+ "os"
+ "strconv"
+)
+
+var decoder = schema.NewDecoder()
+var store = sessions.NewCookieStore([]byte(os.Getenv("SCRIBBLED_SECRET")))
+var mainTempl *template.Template
+var Conf *Configuration
+
+func add(x, y int) int {
+ return x + y
+}
+
+func main() {
+
+ conf_f := flag.String("config", "config.json", "Path to the configuration file.")
+ genConf_f := flag.Bool("genconfig", false, "Generate new configuration file and exit.")
+ flag.Parse()
+
+ if *genConf_f {
+ GenConfig(*conf_f)
+ return
+ }
+
+ Conf = NewConfiguration(*conf_f)
+ Conf.configInit()
+
+ Conf.DB = Conf.NewDatabase()
+ defer func() {
+ if r := recover(); r != nil {
+ log.Println("Recovering", r)
+ defer Conf.DB.Close()
+ }
+ }()
+ defer Conf.DB.Close()
+
+ mainTempl = template.Must(template.New("global").Funcs(template.FuncMap{"add": add, "RenderMarkdown": RenderMarkdown}).ParseGlob(Conf.TemplateDir + "/*.html"))
+
+ decoder.IgnoreUnknownKeys(true)
+ store.Options = &sessions.Options{
+ Path: "/",
+ MaxAge: 86400,
+ HttpOnly: true,
+ }
+
+ r := mux.NewRouter()
+ r.HandleFunc(Conf.VirtualRoot+"/", IndexHandler)
+ r.HandleFunc(Conf.VirtualRoot+"/search", SearchHandler)
+ r.HandleFunc(Conf.VirtualRoot+"/api/new", ApiNewHandler)
+ r.HandleFunc(Conf.VirtualRoot+"/api/get", ApiGetHandler)
+ r.HandleFunc(Conf.VirtualRoot+"/view/{title}", ViewHandler)
+ r.HandleFunc(Conf.VirtualRoot+"/help", PageHandler)
+ r.HandleFunc(Conf.VirtualRoot+"/{title}", ScribbleHandler)
+ r.PathPrefix(Conf.VirtualRoot + "/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(Conf.StaticDir))))
+ r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
+
+ http.Handle("/", r)
+
+ ip := Conf.Ip
+ port := os.Getenv("PORT")
+ if port == "" {
+ port = strconv.Itoa(Conf.Port)
+ }
+
+ log.Println("Starting server listening on " + ip + ":" + port)
+ log.Panic(http.ListenAndServe(ip+":"+port, nil))
+}
diff --git a/scribbled/server.go b/scribbled/server.go
new file mode 100644
index 0000000..d1ea154
--- /dev/null
+++ b/scribbled/server.go
@@ -0,0 +1,70 @@
+package main
+
+import (
+ "encoding/json"
+ "github.com/gorilla/mux"
+ "log"
+ "net/http"
+)
+
+func ExecTemplate(template string, w http.ResponseWriter, r *http.Request, msg ...Note) error {
+ index := mainTempl.Lookup(template)
+
+ note := Note{}
+ if len(msg) > 0 {
+ note = msg[0]
+ }
+ note.VirtualRoot = Conf.VirtualRoot
+
+ /*
+ if note.Title == "" {
+ note.Title = "Welcome"
+ }
+ */
+ err := index.ExecuteTemplate(w, template, note)
+ if err != nil {
+ log.Println("ERROR: ", err)
+ return err
+ }
+ return nil
+}
+
+func ErrorResponse(w http.ResponseWriter, message string, status int) {
+ Response(w, map[string]interface{}{"error": message}, status)
+}
+
+func Response(w http.ResponseWriter, data map[string]interface{}, status ...int) {
+ var responseStatus int
+ if len(status) > 0 {
+ responseStatus = status[0]
+ } else {
+ responseStatus = http.StatusOK
+ }
+
+ w.WriteHeader(responseStatus)
+ w.Header().Set("Content-Type", "application/json")
+
+ resp, _ := json.Marshal(
+ map[string]interface{}{
+ "success": responseStatus == http.StatusOK,
+ "status": responseStatus,
+ "data": data,
+ })
+
+ w.Write(resp)
+}
+
+func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(404)
+
+ vars := mux.Vars(r)
+ note := Note{}
+ note.Title = vars["title"]
+ note.NotFound = true
+
+ err := ExecTemplate("index.html", w, r, note)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
diff --git a/scribbled/struct.go b/scribbled/struct.go
new file mode 100644
index 0000000..61d56f9
--- /dev/null
+++ b/scribbled/struct.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "github.com/syndtr/goleveldb/leveldb"
+)
+
+type Configuration struct {
+ StaticDir string
+ TemplateDir string
+ Port int
+ Ip string
+ VirtualRoot string
+ DatabasePath string
+ DB *leveldb.DB
+}
+
+type Note struct {
+ Title string
+ Post string
+ NotFound bool
+ VirtualRoot string
+}
diff --git a/scribbled/util.go b/scribbled/util.go
new file mode 100644
index 0000000..a1cff0c
--- /dev/null
+++ b/scribbled/util.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+ "os"
+)
+
+func DirExists(filename string) bool {
+ fileInfo, err := os.Stat(filename)
+ return err == nil && fileInfo.IsDir()
+}
+
+func toString(slc []string) string {
+ var s string
+ for _, v := range slc {
+ s = s + " " + v
+ }
+ return s
+}
+
+func Remove(slc []string, s string) []string {
+ var id int
+ for k, v := range slc {
+ if v == s {
+ id = k
+ break
+ }
+ }
+ slc = append(slc[:id], slc[id+1:]...)
+ return slc
+}
diff --git a/scribbled/view.go b/scribbled/view.go
new file mode 100644
index 0000000..b341ee1
--- /dev/null
+++ b/scribbled/view.go
@@ -0,0 +1,78 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/gorilla/mux"
+ "github.com/microcosm-cc/bluemonday"
+ "github.com/russross/blackfriday"
+ "html/template"
+ "io/ioutil"
+ "log"
+ "net/http"
+)
+
+func RenderMarkdown(args ...interface{}) template.HTML {
+ unsafe := blackfriday.MarkdownCommon([]byte(fmt.Sprintf("%s", args...)))
+ html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
+
+ return template.HTML(html)
+}
+
+func ViewHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+
+ note := Note{}
+ note.Title = vars["title"]
+
+ /*
+ err := decoder.Decode(&note, r.Form)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ */
+
+ data, err := Conf.DB.Get([]byte(note.Title), nil)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ NotFoundHandler(w, r)
+ return
+ }
+
+ err = json.Unmarshal(data, &note)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ ErrorResponse(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ err = ExecTemplate("view.html", w, r, note)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+func PageHandler(w http.ResponseWriter, r *http.Request) {
+ page := "Help Page"
+ note := Note{}
+
+ file, err := ioutil.ReadFile(Conf.TemplateDir + "/help.md")
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ note.Title = page
+ note.Post = string(file)
+
+ err = ExecTemplate("view.html", w, r, note)
+ if err != nil {
+ log.Println("ERROR:", err.Error())
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}