From ed4a10c9666cbb0f1b5e48cfb2675da339d44505 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= <torjus@usit.uio.no>
Date: Fri, 21 Jan 2022 07:17:52 +0100
Subject: [PATCH] Add delete

---
 api/http.go                   | 18 ++++++++++++++++
 api/http_test.go              | 40 +++++++++++++++++++++++++++++++++++
 client/client.go              | 21 ++++++++++++++++++
 cmd/client/actions/actions.go | 16 ++++++++++++++
 cmd/client/client.go          |  6 ++++++
 5 files changed, 101 insertions(+)

diff --git a/api/http.go b/api/http.go
index 0a04dd7..148ad34 100644
--- a/api/http.go
+++ b/api/http.go
@@ -49,6 +49,7 @@ func NewHTTPServer(cfg *gpaste.ServerConfig) *HTTPServer {
 	r.Get("/", srv.HandlerIndex)
 	r.Post("/api/file", srv.HandlerAPIFilePost)
 	r.Get("/api/file/{id}", srv.HandlerAPIFileGet)
+	r.Delete("/api/file/{id}", srv.HandlerAPIFileDelete)
 	r.Post("/api/login", srv.HandlerAPILogin)
 	r.Post("/api/user", srv.HandlerAPIUserCreate)
 	srv.Handler = r
@@ -117,6 +118,23 @@ func (s *HTTPServer) HandlerAPIFileGet(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
+func (s *HTTPServer) HandlerAPIFileDelete(w http.ResponseWriter, r *http.Request) {
+	// TODO: Require auth
+	id := chi.URLParam(r, "id")
+	if id == "" {
+		w.WriteHeader(http.StatusBadRequest)
+		return
+	}
+
+	err := s.Files.Delete(id)
+	if err != nil {
+		w.WriteHeader(http.StatusBadRequest)
+		return
+	}
+	reqID := middleware.GetReqID(r.Context())
+	s.Logger.Infow("Deleted file", "id", id, "req_id", reqID)
+}
+
 func (s *HTTPServer) processMultiPartFormUpload(w http.ResponseWriter, r *http.Request) {
 	reqID := middleware.GetReqID(r.Context())
 
diff --git a/api/http_test.go b/api/http_test.go
index 6309384..13081e3 100644
--- a/api/http_test.go
+++ b/api/http_test.go
@@ -8,11 +8,15 @@ import (
 	"mime/multipart"
 	"net/http"
 	"net/http/httptest"
+	"strings"
 	"testing"
+	"time"
 
 	"git.t-juice.club/torjus/gpaste"
 	"git.t-juice.club/torjus/gpaste/api"
+	"git.t-juice.club/torjus/gpaste/files"
 	"git.t-juice.club/torjus/gpaste/users"
+	"github.com/google/uuid"
 )
 
 func TestHandlers(t *testing.T) {
@@ -99,6 +103,42 @@ func TestHandlers(t *testing.T) {
 			}
 		})
 	})
+	t.Run("HandlerAPIFileDelete", func(t *testing.T) {
+		cfg := &gpaste.ServerConfig{
+			SigningSecret: "abc123",
+			Store: &gpaste.ServerStoreConfig{
+				Type: "memory",
+			},
+			URL: "http://localhost:8080",
+		}
+		hs := api.NewHTTPServer(cfg)
+		fileBody := io.NopCloser(strings.NewReader("roflcopter"))
+		file := &files.File{
+			ID:               uuid.NewString(),
+			OriginalFilename: "testpls.txt",
+			MaxViews:         9,
+			ExpiresOn:        time.Now().Add(10 * time.Hour),
+			Body:             fileBody,
+		}
+
+		if err := hs.Files.Store(file); err != nil {
+			t.Fatalf("Error storing file: %s", err)
+		}
+
+		rr := httptest.NewRecorder()
+		url := fmt.Sprintf("/api/file/%s", file.ID)
+		req := httptest.NewRequest(http.MethodDelete, url, nil)
+		hs.Handler.ServeHTTP(rr, req)
+
+		if rr.Result().StatusCode != http.StatusOK {
+			t.Fatalf("Delete returned wrong status: %s", rr.Result().Status)
+		}
+
+		if _, err := hs.Files.Get(file.ID); err == nil {
+			t.Errorf("Getting after delete returned no error")
+		}
+
+	})
 	t.Run("HandlerAPILogin", func(t *testing.T) {
 		// TODO: Add test
 		username := "admin"
diff --git a/client/client.go b/client/client.go
index f787d44..5e76ecc 100644
--- a/client/client.go
+++ b/client/client.go
@@ -203,3 +203,24 @@ func (c *Client) Upload(ctx context.Context, files ...*files.File) ([]api.Respon
 
 	return expectedResp, nil
 }
+
+func (c *Client) Delete(ctx context.Context, id string) error {
+	url := fmt.Sprintf("%s/api/file/%s", c.BaseURL, id)
+
+	req, err := http.NewRequestWithContext(ctx, http.MethodDelete, url, nil)
+	if err != nil {
+		return fmt.Errorf("error creating request: %w", err)
+	}
+
+	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.AuthToken))
+	resp, err := c.httpClient.Do(req)
+	if err != nil {
+		return fmt.Errorf("unable to perform request: %s", err)
+	}
+
+	if resp.StatusCode != http.StatusOK {
+		return fmt.Errorf("got non-ok response from server: %s", resp.Status)
+	}
+
+	return nil
+}
diff --git a/cmd/client/actions/actions.go b/cmd/client/actions/actions.go
index 3270a86..67c5095 100644
--- a/cmd/client/actions/actions.go
+++ b/cmd/client/actions/actions.go
@@ -39,6 +39,22 @@ func ActionUpload(c *cli.Context) error {
 	return nil
 }
 
+func ActionDelete(c *cli.Context) error {
+	clnt := client.Client{
+		BaseURL: c.String("url"),
+	}
+	for _, arg := range c.Args().Slice() {
+		ctx, cancel := context.WithTimeout(c.Context, 5*time.Second)
+		defer cancel()
+		if err := clnt.Delete(ctx, arg); err != nil {
+			fmt.Printf("Error deleting file %s\n", arg)
+			fmt.Printf("%s\n", err)
+		}
+		fmt.Printf("Deleted %s\n", arg)
+	}
+	return nil
+}
+
 func ActionLogin(c *cli.Context) error {
 	username := c.Args().First()
 	if username == "" {
diff --git a/cmd/client/client.go b/cmd/client/client.go
index 3274bcc..35e62c1 100644
--- a/cmd/client/client.go
+++ b/cmd/client/client.go
@@ -37,6 +37,12 @@ func main() {
 				ArgsUsage: "FILE [FILE]...",
 				Action:    actions.ActionUpload,
 			},
+			{
+				Name:      "delete",
+				Usage:     "Delete file(s)",
+				ArgsUsage: "FILE [FILE]...",
+				Action:    actions.ActionDelete,
+			},
 			{
 				Name:      "login",
 				Usage:     "Login to gpaste server",