diff --git a/controller/dictionary.go b/controller/dictionary.go index f403e38..37f997c 100644 --- a/controller/dictionary.go +++ b/controller/dictionary.go @@ -2,6 +2,7 @@ package controller import ( "context" + "github.com/hbl-ngocnd1/dictionary/models" "net/http" "strconv" @@ -24,37 +25,7 @@ func (f *dictHandler) Dict(c echo.Context) error { } func (f *dictHandler) ApiDict(c echo.Context) error { - notCache := c.QueryParam("not_cache") - level := c.QueryParam("level") - start, err := strconv.Atoi(c.QueryParam("start")) - if err != nil { - start = 0 - } - pageSize, err := strconv.Atoi(c.QueryParam("page_size")) - if err != nil { - pageSize = 20 - } - if level == "" { - level = "n1" - } - switch level { - case "n1", "n2", "n3", "n4", "n5": - default: - return c.NoContent(http.StatusBadRequest) - } - pwd := c.QueryParam("password") - ctx := context.Background() - data, err := f.dictUseCase.GetDict(ctx, start, pageSize, notCache, level, pwd) - switch err { - case nil: - case usecase.InvalidErr: - return c.NoContent(http.StatusBadRequest) - case usecase.PermissionDeniedErr: - return c.NoContent(http.StatusForbidden) - default: - return c.String(http.StatusInternalServerError, err.Error()) - } - return c.JSON(http.StatusOK, data) + return getDataJapanese(f, c, models.MakeWord) } func (f *dictHandler) ApiGetDetail(c echo.Context) error { @@ -102,3 +73,37 @@ func (f *dictHandler) ApiITJapanWonderWord(c echo.Context) error { } return c.JSON(http.StatusOK, data) } + +func getDataJapanese(f *dictHandler, c echo.Context, fn models.Fn) error { + notCache := c.QueryParam("not_cache") + level := c.QueryParam("level") + start, err := strconv.Atoi(c.QueryParam("start")) + if err != nil { + start = 0 + } + pageSize, err := strconv.Atoi(c.QueryParam("page_size")) + if err != nil { + pageSize = 20 + } + if level == "" { + level = "n1" + } + switch level { + case "n1", "n2", "n3", "n4", "n5": + default: + return c.NoContent(http.StatusBadRequest) + } + pwd := c.QueryParam("password") + ctx := context.Background() + data, err := f.dictUseCase.GetDict(ctx, start, pageSize, notCache, level, pwd, fn) + switch err { + case nil: + case usecase.InvalidErr: + return c.NoContent(http.StatusBadRequest) + case usecase.PermissionDeniedErr: + return c.NoContent(http.StatusForbidden) + default: + return c.String(http.StatusInternalServerError, err.Error()) + } + return c.JSON(http.StatusOK, data) +} diff --git a/controller/dictionary_test.go b/controller/dictionary_test.go index 0ab93f1..73d8b06 100644 --- a/controller/dictionary_test.go +++ b/controller/dictionary_test.go @@ -40,7 +40,7 @@ func TestNewDictHandler(t *testing.T) { statusCode: http.StatusOK, newMockDictUC: func(ctrl *gomock.Controller) usecase.DictUseCase { mock := mock_usecase.NewMockDictUseCase(ctrl) - mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Word{{}, {}, {}}, nil) + mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Word{{}, {}, {}}, nil) return mock }, }, @@ -54,7 +54,7 @@ func TestNewDictHandler(t *testing.T) { urlParam: "", newMockDictUC: func(ctrl *gomock.Controller) usecase.DictUseCase { mock := mock_usecase.NewMockDictUseCase(ctrl) - mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("unexpected")) + mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("unexpected")) return mock }, statusCode: http.StatusInternalServerError, @@ -65,7 +65,7 @@ func TestNewDictHandler(t *testing.T) { statusCode: http.StatusBadRequest, newMockDictUC: func(ctrl *gomock.Controller) usecase.DictUseCase { mock := mock_usecase.NewMockDictUseCase(ctrl) - mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Word{{}, {}, {}}, usecase.InvalidErr) + mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Word{{}, {}, {}}, usecase.InvalidErr) return mock }, }, @@ -75,7 +75,7 @@ func TestNewDictHandler(t *testing.T) { statusCode: http.StatusForbidden, newMockDictUC: func(ctrl *gomock.Controller) usecase.DictUseCase { mock := mock_usecase.NewMockDictUseCase(ctrl) - mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Word{{}, {}, {}}, usecase.PermissionDeniedErr) + mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Word{{}, {}, {}}, usecase.PermissionDeniedErr) return mock }, }, @@ -85,7 +85,7 @@ func TestNewDictHandler(t *testing.T) { statusCode: http.StatusInternalServerError, newMockDictUC: func(ctrl *gomock.Controller) usecase.DictUseCase { mock := mock_usecase.NewMockDictUseCase(ctrl) - mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Word{{}, {}, {}}, errors.New("another Error")) + mock.EXPECT().GetDict(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Word{{}, {}, {}}, errors.New("another Error")) return mock }, }, diff --git a/models/dictionary.go b/models/dictionary.go index 54f296c..1dcee98 100644 --- a/models/dictionary.go +++ b/models/dictionary.go @@ -7,6 +7,8 @@ import ( "golang.org/x/net/html" ) +type Fn func(c *html.Node, link, detail string, index int) *Word + type Word struct { Index int `json:"index"` Text string `json:"text"` diff --git a/services/dictionary.go b/services/dictionary.go index 4049529..b997b6f 100644 --- a/services/dictionary.go +++ b/services/dictionary.go @@ -24,12 +24,12 @@ func NewDictionary() *dictionaryService { } type DictionaryService interface { - GetDictionary(context.Context, string) ([]models.Word, error) + GetDictionary(context.Context, string, models.Fn) ([]models.Word, error) GetDetail(context.Context, string, int) (string, error) GetITJapanWonderWork(context.Context, string) ([][]models.WonderWord, error) } -func (d *dictionaryService) GetDictionary(ctx context.Context, url string) ([]models.Word, error) { +func (d *dictionaryService) GetDictionary(ctx context.Context, url string, fn models.Fn) ([]models.Word, error) { ctx, cancel := context.WithTimeout(ctx, 50*time.Second) defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) @@ -102,7 +102,7 @@ func (d *dictionaryService) GetDictionary(ctx context.Context, url string) ([]mo log.Println(errDetail) } } - w := models.MakeWord(child, detailURL, detail, id) + w := fn(child, detailURL, detail, id) if w == nil { return } diff --git a/services/dictionary_test.go b/services/dictionary_test.go index 9f1fc5a..7bd397b 100644 --- a/services/dictionary_test.go +++ b/services/dictionary_test.go @@ -3,6 +3,7 @@ package services import ( "context" "fmt" + "github.com/hbl-ngocnd1/dictionary/models" "testing" "github.com/stretchr/testify/assert" @@ -12,7 +13,7 @@ func TestDictionaryService_GetDictionary(t *testing.T) { InitTest() BucketSize = 2 ctx := context.Background() - _, err := NewDictionary().GetDictionary(ctx, "https://japanesetest4you.com/jlpt-n2-vocabulary-list/") + _, err := NewDictionary().GetDictionary(ctx, "https://japanesetest4you.com/jlpt-n2-vocabulary-list/", models.MakeWord) assert.Equal(t, nil, err) } diff --git a/services/mock_services/mock_dictionary.go b/services/mock_services/mock_dictionary.go index 1b3efac..bbd7698 100644 --- a/services/mock_services/mock_dictionary.go +++ b/services/mock_services/mock_dictionary.go @@ -51,18 +51,18 @@ func (mr *MockDictionaryServiceMockRecorder) GetDetail(arg0, arg1, arg2 interfac } // GetDictionary mocks base method. -func (m *MockDictionaryService) GetDictionary(arg0 context.Context, arg1 string) ([]models.Word, error) { +func (m *MockDictionaryService) GetDictionary(arg0 context.Context, arg1 string, arg2 models.Fn) ([]models.Word, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDictionary", arg0, arg1) + ret := m.ctrl.Call(m, "GetDictionary", arg0, arg1, arg2) ret0, _ := ret[0].([]models.Word) ret1, _ := ret[1].(error) return ret0, ret1 } // GetDictionary indicates an expected call of GetDictionary. -func (mr *MockDictionaryServiceMockRecorder) GetDictionary(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockDictionaryServiceMockRecorder) GetDictionary(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDictionary", reflect.TypeOf((*MockDictionaryService)(nil).GetDictionary), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDictionary", reflect.TypeOf((*MockDictionaryService)(nil).GetDictionary), arg0, arg1, arg2) } // GetITJapanWonderWork mocks base method. diff --git a/usecase/dictionary.go b/usecase/dictionary.go index 58e1314..418af63 100644 --- a/usecase/dictionary.go +++ b/usecase/dictionary.go @@ -32,12 +32,12 @@ func NewDictUseCase() *dictUseCase { } type DictUseCase interface { - GetDict(context.Context, int, int, string, string, string) ([]models.Word, error) + GetDict(context.Context, int, int, string, string, string, models.Fn) ([]models.Word, error) GetDetail(context.Context, string, int) (*string, error) GetITJapanWonderWork(context.Context) ([][]models.WonderWord, error) } -func (u *dictUseCase) GetDict(ctx context.Context, start, pageSize int, notCache, level, pwd string) ([]models.Word, error) { +func (u *dictUseCase) GetDict(ctx context.Context, start, pageSize int, notCache, level, pwd string, fn models.Fn) ([]models.Word, error) { if notCache != "true" && u.cacheData != nil && u.cacheData[level] != nil && len(u.cacheData[level]) > 0 { log.Println("use data from cache") if start > len(u.cacheData[level]) { @@ -56,7 +56,7 @@ func (u *dictUseCase) GetDict(ctx context.Context, start, pageSize int, notCache } log.Println("use data from source") url := fmt.Sprintf("https://japanesetest4you.com/jlpt-%s-vocabulary-list/", level) - data, err := u.dictionaryService.GetDictionary(ctx, url) + data, err := u.dictionaryService.GetDictionary(ctx, url, fn) if err != nil { log.Print(err) return nil, err diff --git a/usecase/dictionary_test.go b/usecase/dictionary_test.go index 509cc50..7e911bd 100644 --- a/usecase/dictionary_test.go +++ b/usecase/dictionary_test.go @@ -35,7 +35,7 @@ func Test_GetDict(t *testing.T) { pwd: "sync_pass", newMockDictService: func(ctrl *gomock.Controller) services.DictionaryService { mock := mock_services.NewMockDictionaryService(ctrl) - mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/")).Return([]models.Word{ + mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/"), gomock.Any()).Return([]models.Word{ {}, {}, {}, {}, }, nil) return mock @@ -61,7 +61,7 @@ func Test_GetDict(t *testing.T) { pwd: "sync_pass", newMockDictService: func(ctrl *gomock.Controller) services.DictionaryService { mock := mock_services.NewMockDictionaryService(ctrl) - mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/")).Return([]models.Word{ + mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/"), gomock.Any()).Return([]models.Word{ {}, {}, {}, {}, }, nil) return mock @@ -87,7 +87,7 @@ func Test_GetDict(t *testing.T) { pwd: "sync_pass", newMockDictService: func(ctrl *gomock.Controller) services.DictionaryService { mock := mock_services.NewMockDictionaryService(ctrl) - mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/")).Return([]models.Word{ + mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/"), gomock.Any()).Return([]models.Word{ {}, }, nil) return mock @@ -121,7 +121,7 @@ func Test_GetDict(t *testing.T) { pwd: "sync_pass", newMockDictService: func(ctrl *gomock.Controller) services.DictionaryService { mock := mock_services.NewMockDictionaryService(ctrl) - mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/")).Return([]models.Word{ + mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/"), gomock.Any()).Return([]models.Word{ {}, {}, {}, {}, }, nil) return mock @@ -175,7 +175,7 @@ func Test_GetDict(t *testing.T) { pwd: "sync_pass", newMockDictService: func(ctrl *gomock.Controller) services.DictionaryService { mock := mock_services.NewMockDictionaryService(ctrl) - mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/")).Return([]models.Word{ + mock.EXPECT().GetDictionary(gomock.Any(), gomock.Eq("https://japanesetest4you.com/jlpt-n1-vocabulary-list/"), gomock.Any()).Return([]models.Word{ {}, {}, {}, {}, }, InvalidErr) return mock @@ -225,7 +225,7 @@ func Test_GetDict(t *testing.T) { } ctx := context.Background() os.Setenv("SYNC_PASS", "sync_pass") - actual, err := uc.GetDict(ctx, p.start, p.pageSize, p.notCache, p.level, p.pwd) + actual, err := uc.GetDict(ctx, p.start, p.pageSize, p.notCache, p.level, p.pwd, models.MakeWord) assert.Equal(t, p.expect, actual) assert.Equal(t, p.err, err) }) diff --git a/usecase/mock_usecase/mock_dictionary.go b/usecase/mock_usecase/mock_dictionary.go index 738d700..2802f15 100644 --- a/usecase/mock_usecase/mock_dictionary.go +++ b/usecase/mock_usecase/mock_dictionary.go @@ -51,18 +51,18 @@ func (mr *MockDictUseCaseMockRecorder) GetDetail(arg0, arg1, arg2 interface{}) * } // GetDict mocks base method. -func (m *MockDictUseCase) GetDict(arg0 context.Context, arg1, arg2 int, arg3, arg4, arg5 string) ([]models.Word, error) { +func (m *MockDictUseCase) GetDict(arg0 context.Context, arg1, arg2 int, arg3, arg4, arg5 string, arg6 models.Fn) ([]models.Word, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDict", arg0, arg1, arg2, arg3, arg4, arg5) + ret := m.ctrl.Call(m, "GetDict", arg0, arg1, arg2, arg3, arg4, arg5, arg6) ret0, _ := ret[0].([]models.Word) ret1, _ := ret[1].(error) return ret0, ret1 } // GetDict indicates an expected call of GetDict. -func (mr *MockDictUseCaseMockRecorder) GetDict(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { +func (mr *MockDictUseCaseMockRecorder) GetDict(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDict", reflect.TypeOf((*MockDictUseCase)(nil).GetDict), arg0, arg1, arg2, arg3, arg4, arg5) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDict", reflect.TypeOf((*MockDictUseCase)(nil).GetDict), arg0, arg1, arg2, arg3, arg4, arg5, arg6) } // GetITJapanWonderWork mocks base method.