Skip to content

Commit

Permalink
Bookback (#18)
Browse files Browse the repository at this point in the history
* feat: added minio
  • Loading branch information
SShlykov authored Mar 10, 2024
1 parent 8aa84c6 commit 29f1bff
Show file tree
Hide file tree
Showing 27 changed files with 557 additions and 720 deletions.
4 changes: 2 additions & 2 deletions bookback/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ migrate:

gen_mock:
mockgen \
-source=pkg/db/db.go \
-destination=internal/mocks/db.go \
-source=internal/domain/services/book_service.go \
-destination=tests/mocks/domain/services/book_service_mock.go \
-package=mocks
47 changes: 47 additions & 0 deletions bookback/internal/application/usecase/minio_usecase.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package usecase

import (
"bytes"
"context"
"github.com/SShlykov/zeitment/bookback/internal/models"
"github.com/minio/minio-go/v7"
"io"
)

type MinioUseCase interface {
CreateMinioObject(ctx context.Context, request models.RequestMinioObject) (string, error)
GetMinioObject(ctx context.Context, request models.RequestMinioObject) (*models.MinioResp, error)
}

type minioUseCase struct {
minioClient *minio.Client
}

func NewMinioUseCase(minioClient *minio.Client) MinioUseCase {
return &minioUseCase{minioClient: minioClient}
}

func (ms *minioUseCase) CreateMinioObject(_ context.Context, _ models.RequestMinioObject) (string, error) {
return "", nil
}

func (ms *minioUseCase) GetMinioObject(ctx context.Context, request models.RequestMinioObject) (*models.MinioResp, error) {
reader, err := ms.minioClient.GetObject(ctx, request.BucketName, request.ObjectName, minio.GetObjectOptions{})
if err != nil {
return nil, err
}
defer func(reader *minio.Object) {
_ = reader.Close()
}(reader)

contentBuffer := new(bytes.Buffer)
if _, err = io.Copy(contentBuffer, reader); err != nil {
return nil, err
}
stat, err := reader.Stat()
if err != nil {
return nil, err
}

return &models.MinioResp{ContentType: stat.ContentType, Content: contentBuffer.Bytes(), Name: stat.Key}, nil
}
3 changes: 3 additions & 0 deletions bookback/internal/bootstrap/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/SShlykov/zeitment/bookback/internal/infrastructure/metrics"
"github.com/SShlykov/zeitment/bookback/pkg/config"
"github.com/SShlykov/zeitment/bookback/pkg/postgres"
"github.com/minio/minio-go/v7"

"log/slog"
"os"
Expand All @@ -20,6 +21,7 @@ type App struct {
db postgres.Client
web *endpoint.Handler
metrics metrics.Metrics
minio *minio.Client

ctx context.Context
closeCtx func()
Expand All @@ -34,6 +36,7 @@ func NewApp(configPath string) (*App, error) {
app.initLogger,
app.initMetrics,
app.initDB,
app.initMinio,
app.initWebServer,
}

Expand Down
2 changes: 1 addition & 1 deletion bookback/internal/bootstrap/app/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func (app *App) initWebServer() error {
if err != nil {
return err
}
app.web, err = endpoint.NewHandler(app.db, app.metrics, app.logger, app.ctx, cfg)
app.web, err = endpoint.NewHandler(app.db, app.minio, app.metrics, app.logger, app.ctx, cfg)

if err != nil {
return err
Expand Down
12 changes: 12 additions & 0 deletions bookback/internal/bootstrap/app/minio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app

import "github.com/SShlykov/zeitment/bookback/internal/infrastructure/minio"

Check failure on line 3 in bookback/internal/bootstrap/app/minio.go

View workflow job for this annotation

GitHub Actions / lint

could not import github.com/SShlykov/zeitment/bookback/internal/infrastructure/minio (-: # github.com/SShlykov/zeitment/bookback/internal/infrastructure/minio

func (app *App) initMinio() error {
client, err := minio.NewMinioClient()
if err != nil {
return err
}
app.minio = client
return nil
}
1 change: 1 addition & 0 deletions bookback/internal/domain/entity/book.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func (b Book) AllFields() []string {
"description", "is_public", "publication", "image_link", "map_link", "map_params_id", "variables"}
}

// TODO: Insert or update field
func (b Book) InsertFields() []string {
return []string{"owner", "title", "author", "description", "is_public", "publication", "image_link", "map_link",
"map_params_id", "variables"}
Expand Down
20 changes: 11 additions & 9 deletions bookback/internal/domain/repository/pgrepo/0-genericrepository.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package pgrepo

import (
"context"
"fmt"
"github.com/SShlykov/zeitment/bookback/internal/models/dbutils"
"github.com/SShlykov/zeitment/bookback/pkg/postgres"
"github.com/jackc/pgx/v5"
Expand Down Expand Up @@ -87,7 +86,6 @@ func (r *repository[T]) Create(ctx context.Context, item *T) (string, error) {
if err != nil {
return "", err
}
fmt.Println("query", query)
q := postgres.Query{Name: r.Name + ".Insert", Raw: query}

var id string
Expand All @@ -99,16 +97,20 @@ func (r *repository[T]) Create(ctx context.Context, item *T) (string, error) {
}

func (r *repository[T]) Update(ctx context.Context, id string, item *T) (*T, error) {
updateQuery := r.db.Builder().Update(r.entity.TableName())
insertList := r.entity.EntityToInsertValues(item)
for i, f := range r.entity.InsertFields() {
updateQuery = updateQuery.Set(f, insertList[i])

updateQuery := r.db.Builder().
Update(r.entity.TableName())

for i, field := range r.entity.InsertFields() {
updateQuery = updateQuery.Set(field, insertList[i])
}

query, args, err := updateQuery.
Where(r.entity.TableName()+Equals, id).
Suffix("RETURNING " + strings.Join(r.entity.AllFields(), ", ")).
ToSql()
query, args, err :=
updateQuery.
Where(r.tableKey("id")+Equals, id).
Suffix("RETURNING " + strings.Join(r.entity.AllFields(), ", ")).
ToSql()

if err != nil {
return nil, err
Expand Down
13 changes: 13 additions & 0 deletions bookback/internal/infrastructure/http/v1/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package v1

const (
BasePath = "/api/v1"
BooksPath = BasePath + "/books"
BookEventsPath = BasePath + "/bookevents"
ChaptersPath = BasePath + "/chapters"
MapVariablesPath = BasePath + "/mapvariables"
HealthPath = BasePath + "/health"
PagesPath = BasePath + "/pages"
ParagraphsPath = BasePath + "/paragraphs"
MinioPath = BasePath + "/storage"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package controllers

import (
"context"
v1 "github.com/SShlykov/zeitment/bookback/internal/infrastructure/http/v1"
"github.com/SShlykov/zeitment/bookback/internal/infrastructure/metrics"
"github.com/SShlykov/zeitment/bookback/internal/infrastructure/metrics/localmetrics"
"github.com/SShlykov/zeitment/bookback/internal/models"
"github.com/SShlykov/zeitment/bookback/pkg/logger"
mocks "github.com/SShlykov/zeitment/bookback/tests/mocks/domain/services"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"log/slog"
"net/http"
"net/http/httptest"
"strings"
"testing"
)

var (
lggr *slog.Logger
mtrcs metrics.Metrics
ctx context.Context
RequestBook string
id = "12b9b045-0845-462c-b372-0fca3180a6af"
idPath = v1.BooksPath + "/id"
)

func init() {
lggr = logger.SetupLogger("debug")
mtrcs = localmetrics.NewLocalMetrics(lggr)
ctx = context.Background()
RequestBook = `{"options": {"page": 1, "page_size": 10}}`
return
}

func TestBookController_ListBooks(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

service := mocks.NewMockBookService(ctrl)
listBooks := make([]*models.Book, 0)
service.EXPECT().ListBooks(gomock.Any(), gomock.Any()).Return(listBooks, nil)

e := echo.New()
req := httptest.NewRequest(http.MethodPost, v1.BooksPath+"/list", strings.NewReader(RequestBook))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)

bc := NewBookController(service, mtrcs, lggr, ctx)
err := bc.ListBooks(c)
if err != nil {
return
}

assert.Empty(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
assert.True(t, strings.Contains(rec.Body.String(), `"status":"ok"`))
assert.True(t, strings.Contains(rec.Body.String(), `"data":[]`))
}

func TestBookController_GetBookByID(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

service := mocks.NewMockBookService(ctrl)
book := &models.Book{ID: id}
service.EXPECT().GetBookByID(gomock.Any(), gomock.Any()).Return(book, nil)

e := echo.New()
req := httptest.NewRequest(http.MethodGet, idPath, nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetParamNames("id")
c.SetParamValues(id)

bc := NewBookController(service, mtrcs, lggr, ctx)
err := bc.GetBookByID(c)
if err != nil {
return
}

assert.Empty(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
assert.True(t, strings.Contains(rec.Body.String(), `"status":"ok"`))
assert.True(t, strings.Contains(rec.Body.String(), `"data":`))
assert.True(t, strings.Contains(rec.Body.String(), `"id":"12b9b045-0845-462c-b372-0fca3180a6af"`))
}

func TestBookController_CreateBook(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

service := mocks.NewMockBookService(ctrl)
book := &models.Book{ID: "12b9b045-0845-462c-b372-0fca3180a6af"}
service.EXPECT().CreateBook(gomock.Any(), gomock.Any()).Return(book, nil)

e := echo.New()
req := httptest.NewRequest(http.MethodPost, v1.BooksPath, strings.NewReader(RequestBook))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)

bc := NewBookController(service, mtrcs, lggr, ctx)
err := bc.CreateBook(c)
if err != nil {
return
}

assert.Empty(t, err)
assert.Equal(t, http.StatusCreated, rec.Code)
assert.True(t, strings.Contains(rec.Body.String(), `"status":"created"`))
assert.True(t, strings.Contains(rec.Body.String(), `"data":`))
assert.True(t, strings.Contains(rec.Body.String(), `"id":"12b9b045-0845-462c-b372-0fca3180a6af"`))
}

func TestBookController_UpdateBook(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

service := mocks.NewMockBookService(ctrl)
book := &models.Book{ID: id}
service.EXPECT().UpdateBook(gomock.Any(), gomock.Any(), gomock.Any()).Return(book, nil)

e := echo.New()
req := httptest.NewRequest(http.MethodPut, idPath, strings.NewReader(RequestBook))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetParamNames("id")
c.SetParamValues(id)

bc := NewBookController(service, mtrcs, lggr, ctx)
err := bc.UpdateBook(c)
if err != nil {
return
}

assert.Empty(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
assert.True(t, strings.Contains(rec.Body.String(), `"status":"updated"`))
assert.True(t, strings.Contains(rec.Body.String(), `"data":`))
assert.True(t, strings.Contains(rec.Body.String(), `"id":"12b9b045-0845-462c-b372-0fca3180a6af"`))
}

func TestBookController_DeleteBook(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

service := mocks.NewMockBookService(ctrl)
book := &models.Book{ID: id}
service.EXPECT().DeleteBook(gomock.Any(), gomock.Any()).Return(book, nil)

e := echo.New()
req := httptest.NewRequest(http.MethodDelete, idPath, nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetParamNames("id")
c.SetParamValues(id)

bc := NewBookController(service, mtrcs, lggr, ctx)
err := bc.DeleteBook(c)
if err != nil {
return
}

assert.Empty(t, err)
assert.Equal(t, http.StatusOK, rec.Code)
assert.True(t, strings.Contains(rec.Body.String(), `"status":"deleted"`))
assert.True(t, strings.Contains(rec.Body.String(), `"data":`))
assert.True(t, strings.Contains(rec.Body.String(), `"id":"12b9b045-0845-462c-b372-0fca3180a6af"`))
}
Loading

0 comments on commit 29f1bff

Please sign in to comment.