diff options
Diffstat (limited to 'system/api')
-rw-r--r-- | system/api/create.go (renamed from system/api/external.go) | 48 | ||||
-rw-r--r-- | system/api/delete.go | 140 | ||||
-rw-r--r-- | system/api/handlers.go | 4 | ||||
-rw-r--r-- | system/api/server.go | 4 | ||||
-rw-r--r-- | system/api/update.go | 29 |
5 files changed, 184 insertions, 41 deletions
diff --git a/system/api/external.go b/system/api/create.go index 7f13917..3328bd6 100644 --- a/system/api/external.go +++ b/system/api/create.go @@ -14,20 +14,20 @@ import ( "github.com/ponzu-cms/ponzu/system/item" ) -// Externalable accepts or rejects external POST requests to endpoints such as: -// /api/content/external?type=Review -type Externalable interface { - // Accept allows external content submissions of a specific type - Accept(http.ResponseWriter, *http.Request) error +// Createable accepts or rejects external POST requests to endpoints such as: +// /api/content/create?type=Review +type Createable interface { + // Create enables external clients to submit content of a specific type + Create(http.ResponseWriter, *http.Request) error } // Trustable allows external content to be auto-approved, meaning content sent -// as an Externalable will be stored in the public content bucket +// as an Createable will be stored in the public content bucket type Trustable interface { AutoApprove(http.ResponseWriter, *http.Request) error } -func externalContentHandler(res http.ResponseWriter, req *http.Request) { +func createContentHandler(res http.ResponseWriter, req *http.Request) { if req.Method != http.MethodPost { res.WriteHeader(http.StatusMethodNotAllowed) return @@ -35,7 +35,7 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB if err != nil { - log.Println("[External] error:", err) + log.Println("[Create] error:", err) res.WriteHeader(http.StatusInternalServerError) return } @@ -48,16 +48,16 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { p, found := item.Types[t] if !found { - log.Println("[External] attempt to submit unknown type:", t, "from:", req.RemoteAddr) + log.Println("[Create] attempt to submit unknown type:", t, "from:", req.RemoteAddr) res.WriteHeader(http.StatusNotFound) return } post := p() - ext, ok := post.(Externalable) + ext, ok := post.(Createable) if !ok { - log.Println("[External] rejected non-externalable type:", t, "from:", req.RemoteAddr) + log.Println("[Create] rejected non-createable type:", t, "from:", req.RemoteAddr) res.WriteHeader(http.StatusBadRequest) return } @@ -126,26 +126,26 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { hook, ok := post.(item.Hookable) if !ok { - log.Println("[External] error: Type", t, "does not implement item.Hookable or embed item.Item.") + log.Println("[Create] error: Type", t, "does not implement item.Hookable or embed item.Item.") res.WriteHeader(http.StatusBadRequest) return } - err = hook.BeforeAccept(res, req) + err = hook.BeforeAPICreate(res, req) if err != nil { - log.Println("[External] error calling BeforeAccept:", err) + log.Println("[Create] error calling BeforeAccept:", err) return } - err = ext.Accept(res, req) + err = ext.Create(res, req) if err != nil { - log.Println("[External] error calling Accept:", err) + log.Println("[Create] error calling Accept:", err) return } err = hook.BeforeSave(res, req) if err != nil { - log.Println("[External] error calling BeforeSave:", err) + log.Println("[Create] error calling BeforeSave:", err) return } @@ -160,7 +160,7 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { if ok { err := trusted.AutoApprove(res, req) if err != nil { - log.Println("[External] error calling AutoApprove:", err) + log.Println("[Create] error calling AutoApprove:", err) return } } else { @@ -169,7 +169,7 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { id, err := db.SetContent(t+spec+":-1", req.PostForm) if err != nil { - log.Println("[External] error calling SetContent:", err) + log.Println("[Create] error calling SetContent:", err) res.WriteHeader(http.StatusInternalServerError) return } @@ -180,13 +180,13 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { err = hook.AfterSave(res, req) if err != nil { - log.Println("[External] error calling AfterSave:", err) + log.Println("[Create] error calling AfterSave:", err) return } - err = hook.AfterAccept(res, req) + err = hook.AfterAPICreate(res, req) if err != nil { - log.Println("[External] error calling AfterAccept:", err) + log.Println("[Create] error calling AfterAccept:", err) return } @@ -215,7 +215,7 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { j, err := json.Marshal(resp) if err != nil { - log.Println("[External] error marshalling response to JSON:", err) + log.Println("[Create] error marshalling response to JSON:", err) res.WriteHeader(http.StatusInternalServerError) return } @@ -223,7 +223,7 @@ func externalContentHandler(res http.ResponseWriter, req *http.Request) { res.Header().Set("Content-Type", "application/json") _, err = res.Write(j) if err != nil { - log.Println("[External] error writing response:", err) + log.Println("[Create] error writing response:", err) return } diff --git a/system/api/delete.go b/system/api/delete.go new file mode 100644 index 0000000..36f2b1b --- /dev/null +++ b/system/api/delete.go @@ -0,0 +1,140 @@ +package api + +import ( + "encoding/json" + "log" + "net/http" + + "github.com/ponzu-cms/ponzu/system/db" + "github.com/ponzu-cms/ponzu/system/item" +) + +// Deleteable accepts or rejects update POST requests to endpoints such as: +// /api/content/delete?type=Review&id=1 +type Deleteable interface { + // Delete enables external clients to delete content of a specific type + Delete(http.ResponseWriter, *http.Request) error +} + +func deleteContentHandler(res http.ResponseWriter, req *http.Request) { + if req.Method != http.MethodPost { + res.WriteHeader(http.StatusMethodNotAllowed) + return + } + + err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB + if err != nil { + log.Println("[Delete] error:", err) + res.WriteHeader(http.StatusInternalServerError) + return + } + + t := req.URL.Query().Get("type") + if t == "" { + res.WriteHeader(http.StatusBadRequest) + return + } + + p, found := item.Types[t] + if !found { + log.Println("[Delete] attempt to delete content of unknown type:", t, "from:", req.RemoteAddr) + res.WriteHeader(http.StatusNotFound) + return + } + + id := req.URL.Query().Get("id") + if !db.IsValidID(id) { + log.Println("[Delete] attempt to delete content with missing or invalid id from:", req.RemoteAddr) + res.WriteHeader(http.StatusBadRequest) + return + } + + post := p() + + ext, ok := post.(Deleteable) + if !ok { + log.Println("[Delete] rejected non-deleteable type:", t, "from:", req.RemoteAddr) + res.WriteHeader(http.StatusBadRequest) + return + } + + hook, ok := post.(item.Hookable) + if !ok { + log.Println("[Delete] error: Type", t, "does not implement item.Hookable or embed item.Item.") + res.WriteHeader(http.StatusBadRequest) + return + } + + err = hook.BeforeAPIDelete(res, req) + if err != nil { + log.Println("[Delete] error calling BeforeAPIDelete:", err) + if err == ErrNoAuth { + // BeforeAPIDelete can check user.IsValid(req) for auth + res.WriteHeader(http.StatusUnauthorized) + } + return + } + + err = ext.Delete(res, req) + if err != nil { + log.Println("[Delete] error calling Delete:", err) + if err == ErrNoAuth { + // Delete can check user.IsValid(req) or other forms of validation for auth + res.WriteHeader(http.StatusUnauthorized) + } + return + } + + err = hook.BeforeDelete(res, req) + if err != nil { + log.Println("[Delete] error calling BeforeSave:", err) + return + } + + err = db.DeleteContent(t + ":" + id) + if err != nil { + log.Println("[Delete] error calling DeleteContent:", err) + res.WriteHeader(http.StatusInternalServerError) + return + } + + err = hook.AfterDelete(res, req) + if err != nil { + log.Println("[Delete] error calling AfterDelete:", err) + return + } + + err = hook.AfterAPIDelete(res, req) + if err != nil { + log.Println("[Delete] error calling AfterAPIDelete:", err) + return + } + + // create JSON response to send data back to client + var data = map[string]interface{}{ + "id": id, + "status": "deleted", + "type": t, + } + + resp := map[string]interface{}{ + "data": []map[string]interface{}{ + data, + }, + } + + j, err := json.Marshal(resp) + if err != nil { + log.Println("[Delete] error marshalling response to JSON:", err) + res.WriteHeader(http.StatusInternalServerError) + return + } + + res.Header().Set("Content-Type", "application/json") + _, err = res.Write(j) + if err != nil { + log.Println("[Delete] error writing response:", err) + return + } + +} diff --git a/system/api/handlers.go b/system/api/handlers.go index 4a9eaff..83bbe43 100644 --- a/system/api/handlers.go +++ b/system/api/handlers.go @@ -2,6 +2,7 @@ package api import ( "encoding/json" + "errors" "log" "net/http" "strconv" @@ -11,6 +12,9 @@ import ( "github.com/ponzu-cms/ponzu/system/item" ) +// ErrNoAuth should be used to report failed auth requests +var ErrNoAuth = errors.New("Auth failed for request") + // deprecating from API, but going to provide code here in case someone wants it func typesHandler(res http.ResponseWriter, req *http.Request) { var types = []string{} diff --git a/system/api/server.go b/system/api/server.go index 6a848dd..c568877 100644 --- a/system/api/server.go +++ b/system/api/server.go @@ -8,7 +8,9 @@ func Run() { http.HandleFunc("/api/content", Record(CORS(Gzip(contentHandler)))) - http.HandleFunc("/api/content/external", Record(CORS(externalContentHandler))) + http.HandleFunc("/api/content/create", Record(CORS(createContentHandler))) http.HandleFunc("/api/content/update", Record(CORS(updateContentHandler))) + + http.HandleFunc("/api/content/delete", Record(CORS(deleteContentHandler))) } diff --git a/system/api/update.go b/system/api/update.go index 3a92a84..f7f7346 100644 --- a/system/api/update.go +++ b/system/api/update.go @@ -3,7 +3,6 @@ package api import ( "context" "encoding/json" - "errors" "fmt" "log" "net/http" @@ -15,13 +14,11 @@ import ( "github.com/ponzu-cms/ponzu/system/item" ) -var ErrNoAuth = errors.New("Auth failed for update request.") - // Updateable accepts or rejects update POST requests to endpoints such as: // /api/content/update?type=Review&id=1 type Updateable interface { - // AcceptUpdate allows external content update submissions of a specific type - AcceptUpdate(http.ResponseWriter, *http.Request) error + // Update enabled external clients to update content of a specific type + Update(http.ResponseWriter, *http.Request) error } func updateContentHandler(res http.ResponseWriter, req *http.Request) { @@ -45,14 +42,14 @@ func updateContentHandler(res http.ResponseWriter, req *http.Request) { p, found := item.Types[t] if !found { - log.Println("[Update] attempt to submit unknown type:", t, "from:", req.RemoteAddr) + log.Println("[Update] attempt to update content unknown type:", t, "from:", req.RemoteAddr) res.WriteHeader(http.StatusNotFound) return } id := req.URL.Query().Get("id") if !db.IsValidID(id) { - log.Println("[Update] attempt to submit update with missing or invalid id from:", req.RemoteAddr) + log.Println("[Update] attempt to update content with missing or invalid id from:", req.RemoteAddr) res.WriteHeader(http.StatusBadRequest) return } @@ -135,21 +132,21 @@ func updateContentHandler(res http.ResponseWriter, req *http.Request) { return } - err = hook.BeforeAcceptUpdate(res, req) + err = hook.BeforeAPIUpdate(res, req) if err != nil { - log.Println("[Update] error calling BeforeAcceptUpdate:", err) + log.Println("[Update] error calling BeforeAPIUpdate:", err) if err == ErrNoAuth { - // BeforeAcceptUpdate can check user.IsValid(req) for auth + // BeforeAPIUpdate can check user.IsValid(req) for auth res.WriteHeader(http.StatusUnauthorized) } return } - err = ext.AcceptUpdate(res, req) + err = ext.Update(res, req) if err != nil { - log.Println("[Update] error calling AcceptUpdate:", err) + log.Println("[Update] error calling Update:", err) if err == ErrNoAuth { - // AcceptUpdate can check user.IsValid(req) for auth + // Update can check user.IsValid(req) or other forms of validation for auth res.WriteHeader(http.StatusUnauthorized) } return @@ -172,7 +169,7 @@ func updateContentHandler(res http.ResponseWriter, req *http.Request) { } // set the target in the context so user can get saved value from db in hook - ctx := context.WithValue(req.Context(), "target", fmt.Sprintf("%s:%d", t, id)) + ctx := context.WithValue(req.Context(), "target", fmt.Sprintf("%s:%s", t, id)) req = req.WithContext(ctx) err = hook.AfterSave(res, req) @@ -181,9 +178,9 @@ func updateContentHandler(res http.ResponseWriter, req *http.Request) { return } - err = hook.AfterAcceptUpdate(res, req) + err = hook.AfterAPIUpdate(res, req) if err != nil { - log.Println("[Update] error calling AfterAcceptUpdate:", err) + log.Println("[Update] error calling AfterAPIUpdate:", err) return } |