diff options
author | Baitinq <manuelpalenzuelamerino@gmail.com> | 2024-08-19 00:11:32 +0200 |
---|---|---|
committer | Baitinq <manuelpalenzuelamerino@gmail.com> | 2024-08-19 00:14:38 +0200 |
commit | 1aafb164f51992fad314e612afaff8b1b0367447 (patch) | |
tree | 9b1270a0fc18baf66f14da05b7d7c777cc0c7594 | |
parent | Migrations: Add new restored_file table migration (diff) | |
download | fs-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-x | requests_examples.sh | 1 | ||||
-rw-r--r-- | src/rest-api/cmd/main.go | 1 | ||||
-rw-r--r-- | src/rest-api/handler/db.go | 22 | ||||
-rw-r--r-- | src/rest-api/handler/handler.go | 45 | ||||
-rw-r--r-- | src/rest-api/handler/handler_test.go | 48 | ||||
-rw-r--r-- | src/rest-api/handler/mock_db.go | 19 |
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() |