about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <manuelpalenzuelamerino@gmail.com>2024-08-19 00:11:32 +0200
committerBaitinq <manuelpalenzuelamerino@gmail.com>2024-08-19 00:14:38 +0200
commit1aafb164f51992fad314e612afaff8b1b0367447 (patch)
tree9b1270a0fc18baf66f14da05b7d7c777cc0c7594
parentMigrations: Add new restored_file table migration (diff)
downloadfs-tracer-backend-1aafb164f51992fad314e612afaff8b1b0367447.tar.gz
fs-tracer-backend-1aafb164f51992fad314e612afaff8b1b0367447.tar.bz2
fs-tracer-backend-1aafb164f51992fad314e612afaff8b1b0367447.zip
rest-api: Add /api/v1/restored-files/ endpoint
-rwxr-xr-xrequests_examples.sh1
-rw-r--r--src/rest-api/cmd/main.go1
-rw-r--r--src/rest-api/handler/db.go22
-rw-r--r--src/rest-api/handler/handler.go45
-rw-r--r--src/rest-api/handler/handler_test.go48
-rw-r--r--src/rest-api/handler/mock_db.go19
6 files changed, 130 insertions, 6 deletions
diff --git a/requests_examples.sh b/requests_examples.sh
index 585707f..af54f89 100755
--- a/requests_examples.sh
+++ b/requests_examples.sh
@@ -15,3 +15,4 @@ curl -H "API_KEY: ${FS_TRACER_API_KEY}" -X POST -d '
 
 curl -H "API_KEY: ${FS_TRACER_API_KEY}" -X GET http://leunam.dev:9999/api/v1/file/?path=%2Fhome%2Fuser%2Ffile.txt
 
+# curl -H "API_KEY: ${FS_TRACER_API_KEY}" -X GET http://leunam.dev:9999/api/v1/restored-files/
diff --git a/src/rest-api/cmd/main.go b/src/rest-api/cmd/main.go
index f8e3e2f..b1d2665 100644
--- a/src/rest-api/cmd/main.go
+++ b/src/rest-api/cmd/main.go
@@ -70,6 +70,7 @@ func main() {
 		fmt.Fprint(w, "Hello folks!")
 	})
 	mux.Handle("/api/v1/file/", handler)
+	mux.Handle("/api/v1/restored-files/", handler)
 
 	http.ListenAndServe(":8080", mux)
 }
diff --git a/src/rest-api/handler/db.go b/src/rest-api/handler/db.go
index fc32f5c..65ca8b2 100644
--- a/src/rest-api/handler/db.go
+++ b/src/rest-api/handler/db.go
@@ -11,6 +11,7 @@ import (
 type DB interface {
 	GetLatestFileByPath(ctx context.Context, path string, user_id string) (*lib.File, error)
 	GetUserIDByAPIKey(ctx context.Context, apiKey string) (string, error)
+	GetAndDeleteRestoredFiles(ctx context.Context, user_id string) (*[]lib.File, error)
 }
 
 type DBImpl struct {
@@ -39,6 +40,27 @@ func (db DBImpl) GetLatestFileByPath(ctx context.Context, path string, user_id s
 	return &file, nil
 }
 
+func (db DBImpl) GetAndDeleteRestoredFiles(ctx context.Context, user_id string) (*[]lib.File, error) {
+	var files []lib.File
+	err := db.db.SelectContext(ctx, &files, `
+		SELECT * FROM public.restored_file
+		WHERE user_id = $1
+	`, user_id)
+	if err != nil {
+		return nil, err
+	}
+
+	_, err = db.db.ExecContext(ctx, `
+		DELETE FROM public.restored_file
+		WHERE user_id = $1
+	`, user_id)
+	if err != nil {
+		return nil, err
+	}
+
+	return &files, nil
+}
+
 // TODO: Add test
 func (db DBImpl) GetUserIDByAPIKey(ctx context.Context, apiKey string) (string, error) {
 	if len(apiKey) != 44 {
diff --git a/src/rest-api/handler/handler.go b/src/rest-api/handler/handler.go
index 354378f..1aa618b 100644
--- a/src/rest-api/handler/handler.go
+++ b/src/rest-api/handler/handler.go
@@ -2,10 +2,12 @@ package handler
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"io"
 	"log"
 	"net/http"
+	"strings"
 	"time"
 
 	"github.com/jmoiron/sqlx"
@@ -53,6 +55,18 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 }
 
 func (h Handler) handleGet(w http.ResponseWriter, r *http.Request, user_id string) {
+	if strings.Contains(r.URL.Path, "/file/") {
+		h.handleGetFile(w, r, user_id)
+	} else if strings.Contains(r.URL.Path, "/restored-files/") {
+		h.handleGetRestoredFiles(w, r, user_id)
+	} else {
+		fmt.Println("Path: ", r.URL.Path)
+		http.NotFound(w, r)
+	}
+
+}
+
+func (h Handler) handleGetFile(w http.ResponseWriter, r *http.Request, user_id string) {
 	filePath := r.URL.Query().Get("path")
 	if filePath == "" {
 		http.Error(w, "Invalid file path", http.StatusBadRequest)
@@ -69,10 +83,39 @@ func (h Handler) handleGet(w http.ResponseWriter, r *http.Request, user_id strin
 		return
 	}
 
-	fmt.Fprintln(w, "File: ", file)
+	bytes, err := json.Marshal(file)
+	if err != nil {
+		http.Error(w, fmt.Sprintf("Internal server error: %s", err), http.StatusInternalServerError)
+		return
+	}
+
+	fmt.Fprint(w, string(bytes))
+}
+
+func (h Handler) handleGetRestoredFiles(w http.ResponseWriter, r *http.Request, user_id string) {
+	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
+	defer cancel()
+	files, err := h.db.GetAndDeleteRestoredFiles(ctx, user_id)
+	if err != nil {
+		http.Error(w, fmt.Sprintf("Internal server error: %s", err), http.StatusInternalServerError)
+		return
+	}
+
+	bytes, err := json.Marshal(files)
+	if err != nil {
+		http.Error(w, fmt.Sprintf("Internal server error: %s", err), http.StatusInternalServerError)
+		return
+	}
+
+	fmt.Fprint(w, string(bytes))
 }
 
 func (h Handler) handlePost(w http.ResponseWriter, r *http.Request, user_id string) {
+	if !strings.Contains(r.URL.Path, "/file/") {
+		http.NotFound(w, r)
+		return
+	}
+
 	bytes, err := io.ReadAll(io.Reader(r.Body))
 	if err != nil {
 		log.Fatal(err)
diff --git a/src/rest-api/handler/handler_test.go b/src/rest-api/handler/handler_test.go
index 183d584..e3dbfe0 100644
--- a/src/rest-api/handler/handler_test.go
+++ b/src/rest-api/handler/handler_test.go
@@ -1,31 +1,73 @@
 package handler
 
 import (
-	"fmt"
 	"net/http"
 	"net/http/httptest"
+	"strings"
 	"testing"
+	"time"
 
 	"github.com/Baitinq/fs-tracer-backend/lib"
 	"github.com/stretchr/testify/require"
 	gomock "go.uber.org/mock/gomock"
 )
 
-func TestHandleGet(t *testing.T) {
+func TestHandleGetFile(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	db := NewMockDB(ctrl)
 	recorder := httptest.NewRecorder()
 
 	handler := Handler{db: db}
 
+	now := time.Now()
 	file := &lib.File{
+		Id:            "ID",
 		User_id:       "USER_ID",
 		Absolute_path: "/tmp/file.txt",
+		Timestamp:     now,
+		Contents:      "contents",
 	}
 	db.EXPECT().GetLatestFileByPath(gomock.Any(), "/tmp/file.txt", "USER_ID").Return(file, nil)
 
 	handler.handleGet(recorder, httptest.NewRequest(http.MethodGet, "/file/?path=%2ftmp%2Ffile.txt", nil), "USER_ID")
 
 	require.Equal(t, http.StatusOK, recorder.Code)
-	require.Equal(t, fmt.Sprintln("File: ", file), recorder.Body.String())
+	require.Equal(t, strings.Join(strings.Fields(`
+		{
+			"Id": "ID",
+			"User_id": "USER_ID",
+			"Absolute_path": "/tmp/file.txt",
+			"Contents": "contents",
+			"Timestamp": "`+now.Format(time.RFC3339Nano)+`"
+		}`), ""), recorder.Body.String())
+}
+
+func TestHandleGetRestoredFiles(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	db := NewMockDB(ctrl)
+	recorder := httptest.NewRecorder()
+
+	handler := Handler{db: db}
+
+	now := time.Now()
+	file := &lib.File{
+		Id:            "ID",
+		User_id:       "USER_ID",
+		Absolute_path: "/tmp/file.txt",
+		Timestamp:     now,
+		Contents:      "contents",
+	}
+	db.EXPECT().GetAndDeleteRestoredFiles(gomock.Any(), "USER_ID").Return(&[]lib.File{*file}, nil)
+
+	handler.handleGet(recorder, httptest.NewRequest(http.MethodGet, "/restored-files/", nil), "USER_ID")
+
+	require.Equal(t, http.StatusOK, recorder.Code)
+	require.Equal(t, strings.Join(strings.Fields(`[
+		{
+			"Id": "ID",
+			"User_id": "USER_ID",
+			"Absolute_path": "/tmp/file.txt",
+			"Contents": "contents",
+			"Timestamp": "`+now.Format(time.RFC3339Nano)+`"
+		}]`), ""), recorder.Body.String())
 }
diff --git a/src/rest-api/handler/mock_db.go b/src/rest-api/handler/mock_db.go
index 542fd62..bb613c6 100644
--- a/src/rest-api/handler/mock_db.go
+++ b/src/rest-api/handler/mock_db.go
@@ -1,9 +1,9 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: src/rest-api/handler/db.go
+// Source: db.go
 //
 // Generated by this command:
 //
-//	mockgen -source src/rest-api/handler/db.go -package handler -destination=src/rest-api/handler/mock_db.go
+//	mockgen -source=db.go -package=handler -destination=mock_db.go
 //
 
 // Package handler is a generated GoMock package.
@@ -40,6 +40,21 @@ func (m *MockDB) EXPECT() *MockDBMockRecorder {
 	return m.recorder
 }
 
+// GetAndDeleteRestoredFiles mocks base method.
+func (m *MockDB) GetAndDeleteRestoredFiles(ctx context.Context, user_id string) (*[]lib.File, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetAndDeleteRestoredFiles", ctx, user_id)
+	ret0, _ := ret[0].(*[]lib.File)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetAndDeleteRestoredFiles indicates an expected call of GetAndDeleteRestoredFiles.
+func (mr *MockDBMockRecorder) GetAndDeleteRestoredFiles(ctx, user_id any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAndDeleteRestoredFiles", reflect.TypeOf((*MockDB)(nil).GetAndDeleteRestoredFiles), ctx, user_id)
+}
+
 // GetLatestFileByPath mocks base method.
 func (m *MockDB) GetLatestFileByPath(ctx context.Context, path, user_id string) (*lib.File, error) {
 	m.ctrl.T.Helper()