summaryrefslogtreecommitdiff
path: root/system/api
diff options
context:
space:
mode:
Diffstat (limited to 'system/api')
-rw-r--r--system/api/analytics/init.go4
-rw-r--r--system/api/external.go134
-rw-r--r--system/api/handlers.go6
-rw-r--r--system/api/server.go6
4 files changed, 90 insertions, 60 deletions
diff --git a/system/api/analytics/init.go b/system/api/analytics/init.go
index 41c24c7..6558adf 100644
--- a/system/api/analytics/init.go
+++ b/system/api/analytics/init.go
@@ -66,7 +66,7 @@ func Init() {
}
err = store.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucketIfNotExists([]byte("requests"))
+ _, err := tx.CreateBucketIfNotExists([]byte("__requests"))
if err != nil {
return err
}
@@ -138,7 +138,7 @@ func ChartData() (map[string]interface{}, error) {
// get api request analytics from db
var requests = []apiRequest{}
err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("requests"))
+ b := tx.Bucket([]byte("__requests"))
err := b.ForEach(func(k, v []byte) error {
var r apiRequest
diff --git a/system/api/external.go b/system/api/external.go
index 4e008af..0d1ea03 100644
--- a/system/api/external.go
+++ b/system/api/external.go
@@ -15,11 +15,17 @@ import (
// Externalable accepts or rejects external POST requests to endpoints such as:
// /external/content?type=Review
type Externalable interface {
- // Accepts determines whether a type will allow external submissions
- Accepts() bool
+ // Accept allows external content submissions of a specific type
+ Accept(req *http.Request) error
}
-func externalPostHandler(res http.ResponseWriter, req *http.Request) {
+// Trustable allows external content to be auto-approved, meaning content sent
+// as an Externalable will be stored in the public content bucket
+type Trustable interface {
+ AutoApprove(req *http.Request) error
+}
+
+func externalContentHandler(res http.ResponseWriter, req *http.Request) {
if req.Method != http.MethodPost {
res.WriteHeader(http.StatusMethodNotAllowed)
return
@@ -54,69 +60,93 @@ func externalPostHandler(res http.ResponseWriter, req *http.Request) {
return
}
- if ext.Accepts() {
- ts := fmt.Sprintf("%d", time.Now().Unix()*1000)
- req.PostForm.Set("timestamp", ts)
- req.PostForm.Set("updated", ts)
+ ts := fmt.Sprintf("%d", time.Now().Unix()*1000)
+ req.PostForm.Set("timestamp", ts)
+ req.PostForm.Set("updated", ts)
- urlPaths, err := upload.StoreFiles(req)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
+ urlPaths, err := upload.StoreFiles(req)
+ if err != nil {
+ log.Println(err)
+ res.WriteHeader(http.StatusInternalServerError)
+ return
+ }
- for name, urlPath := range urlPaths {
- req.PostForm.Add(name, urlPath)
- }
+ for name, urlPath := range urlPaths {
+ req.PostForm.Set(name, urlPath)
+ }
- // check for any multi-value fields (ex. checkbox fields)
- // and correctly format for db storage. Essentially, we need
- // fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2}
- var discardKeys []string
- for k, v := range req.PostForm {
- if strings.Contains(k, ".") {
- key := strings.Split(k, ".")[0]
-
- if req.PostForm.Get(key) == "" {
- req.PostForm.Set(key, v[0])
- discardKeys = append(discardKeys, k)
- } else {
- req.PostForm.Add(key, v[0])
- }
+ // check for any multi-value fields (ex. checkbox fields)
+ // and correctly format for db storage. Essentially, we need
+ // fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2}
+ var discardKeys []string
+ for k, v := range req.PostForm {
+ if strings.Contains(k, ".") {
+ key := strings.Split(k, ".")[0]
+
+ if req.PostForm.Get(key) == "" {
+ req.PostForm.Set(key, v[0])
+ discardKeys = append(discardKeys, k)
+ } else {
+ req.PostForm.Add(key, v[0])
}
}
+ }
- for _, discardKey := range discardKeys {
- req.PostForm.Del(discardKey)
- }
+ for _, discardKey := range discardKeys {
+ req.PostForm.Del(discardKey)
+ }
- hook, ok := post.(content.Hookable)
- if !ok {
- log.Println("[External] error: Type", t, "does not implement content.Hookable or embed content.Item.")
- res.WriteHeader(http.StatusBadRequest)
- return
- }
+ // call Accept with the request, enabling developer to add or chack data
+ // before saving to DB
+ err = ext.Accept(req)
+ if err != nil {
+ log.Println(err)
+ res.WriteHeader(http.StatusInternalServerError)
+ return
+ }
- err = hook.BeforeSave(req)
- if err != nil {
- log.Println("[External] error:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
+ hook, ok := post.(content.Hookable)
+ if !ok {
+ log.Println("[External] error: Type", t, "does not implement content.Hookable or embed content.Item.")
+ res.WriteHeader(http.StatusBadRequest)
+ return
+ }
- _, err = db.SetContent(t+"_pending:-1", req.PostForm)
- if err != nil {
- log.Println("[External] error:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
+ err = hook.BeforeSave(req)
+ if err != nil {
+ log.Println("[External] error:", err)
+ res.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ // set specifier for db bucket in case content is/isn't Trustable
+ var spec string
- err = hook.AfterSave(req)
+ // check if the content is Trustable should be auto-approved
+ trusted, ok := post.(Trustable)
+ if ok {
+ err := trusted.AutoApprove(req)
if err != nil {
log.Println("[External] error:", err)
res.WriteHeader(http.StatusInternalServerError)
return
}
+ } else {
+ spec = "__pending"
}
+
+ _, err = db.SetContent(t+spec+":-1", req.PostForm)
+ if err != nil {
+ log.Println("[External] error:", err)
+ res.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ err = hook.AfterSave(req)
+ if err != nil {
+ log.Println("[External] error:", err)
+ res.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
}
diff --git a/system/api/handlers.go b/system/api/handlers.go
index afe5819..8a1517b 100644
--- a/system/api/handlers.go
+++ b/system/api/handlers.go
@@ -28,7 +28,7 @@ func typesHandler(res http.ResponseWriter, req *http.Request) {
sendData(res, j, http.StatusOK)
}
-func postsHandler(res http.ResponseWriter, req *http.Request) {
+func contentsHandler(res http.ResponseWriter, req *http.Request) {
q := req.URL.Query()
t := q.Get("type")
if t == "" {
@@ -72,7 +72,7 @@ func postsHandler(res http.ResponseWriter, req *http.Request) {
Order: order,
}
- bb := db.Query(t+"_sorted", opts)
+ _, bb := db.Query(t+"__sorted", opts)
var result = []json.RawMessage{}
for i := range bb {
result = append(result, bb[i])
@@ -87,7 +87,7 @@ func postsHandler(res http.ResponseWriter, req *http.Request) {
sendData(res, j, http.StatusOK)
}
-func postHandler(res http.ResponseWriter, req *http.Request) {
+func contentHandler(res http.ResponseWriter, req *http.Request) {
q := req.URL.Query()
id := q.Get("id")
t := q.Get("type")
diff --git a/system/api/server.go b/system/api/server.go
index 70add10..823ec16 100644
--- a/system/api/server.go
+++ b/system/api/server.go
@@ -8,9 +8,9 @@ import (
func Run() {
http.HandleFunc("/api/types", CORS(Record(typesHandler)))
- http.HandleFunc("/api/contents", CORS(Record(postsHandler)))
+ http.HandleFunc("/api/contents", CORS(Record(contentsHandler)))
- http.HandleFunc("/api/content", CORS(Record(postHandler)))
+ http.HandleFunc("/api/content", CORS(Record(contentHandler)))
- http.HandleFunc("/api/content/external", CORS(Record(externalPostHandler)))
+ http.HandleFunc("/api/content/external", CORS(Record(externalContentHandler)))
}