add filters to cli and client
This commit is contained in:
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.loyso.art/frx/kurious/internal/common/client/sravni"
|
||||
"git.loyso.art/frx/kurious/internal/common/errors"
|
||||
@ -35,9 +36,17 @@ func setupAPICommand(ctx context.Context) cli.Command {
|
||||
WithOption(offsetOption).
|
||||
WithAction(newListProductAction(ctx))
|
||||
})
|
||||
apiEducationFilterCount := buildCLICommand(func() cli.Command {
|
||||
return cli.NewCommand("filter_count", "Loads counts of returned entities").
|
||||
WithOption(learningTypeOpt).
|
||||
WithOption(courseThematic).
|
||||
WithOption(learningSelectionOpt).
|
||||
WithAction(newProductsFilterCountAction(ctx))
|
||||
})
|
||||
|
||||
apiEducation := cli.NewCommand("education", "Education related category").
|
||||
WithCommand(apiEducationListProducts)
|
||||
WithCommand(apiEducationListProducts).
|
||||
WithCommand(apiEducationFilterCount)
|
||||
|
||||
return cli.NewCommand("api", "Interaction with API").
|
||||
WithCommand(apiEducation)
|
||||
@ -127,7 +136,7 @@ func (a *listProductsAction) parse(args []string, options map[string]string) err
|
||||
func (a *listProductsAction) handle() error {
|
||||
params := sravni.ListEducationProductsParams{
|
||||
LearningType: a.params.learningType,
|
||||
CoursesThematics: a.params.courseThematic,
|
||||
CoursesThematics: []string{a.params.courseThematic},
|
||||
Limit: a.params.limit,
|
||||
Offset: a.params.offset,
|
||||
}
|
||||
@ -140,3 +149,65 @@ func (a *listProductsAction) handle() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type productsFilterCountActionParams struct {
|
||||
learningType string
|
||||
courseThematic []string
|
||||
learningSelectionType string
|
||||
}
|
||||
|
||||
type productsFilterCountAction struct {
|
||||
*baseAction
|
||||
|
||||
client sravni.Client
|
||||
params productsFilterCountActionParams
|
||||
}
|
||||
|
||||
func newProductsFilterCountAction(ctx context.Context) cli.Action {
|
||||
action := &productsFilterCountAction{
|
||||
baseAction: newBaseAction(ctx),
|
||||
}
|
||||
|
||||
return asCLIAction(action)
|
||||
}
|
||||
|
||||
func (a *productsFilterCountAction) parse(args []string, options map[string]string) error {
|
||||
err := a.baseAction.parse(args, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
|
||||
a.params.learningType, ok = options[learningTypeOptName]
|
||||
if !ok {
|
||||
return errors.SimpleError(learningTypeOptName + " is empty")
|
||||
}
|
||||
|
||||
a.params.courseThematic = strings.Split(options[courseThematicOptName], ",")
|
||||
a.params.learningSelectionType = options[learningTypeSelectionOptName]
|
||||
|
||||
client, err := makeSravniClient(a.ctx, a.log, options)
|
||||
if err != nil {
|
||||
return fmt.Errorf("making sravni client: %w", err)
|
||||
}
|
||||
|
||||
a.client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *productsFilterCountAction) handle() error {
|
||||
params := sravni.ListEducationProductsParams{
|
||||
LearningType: a.params.learningType,
|
||||
CoursesThematics: a.params.courseThematic,
|
||||
}
|
||||
result, err := a.client.ListEducationalProductsFilterCount(a.ctx, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing education products: %w", err)
|
||||
}
|
||||
|
||||
a.log.InfoContext(a.ctx, "list education products result", slog.Any("result", result))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -29,7 +29,11 @@ type Client interface {
|
||||
ListEducationalProducts(
|
||||
ctx context.Context,
|
||||
params ListEducationProductsParams,
|
||||
) (result ListEducationProductsResponse, err error)
|
||||
) (result listEducationProductsResponse, err error)
|
||||
ListEducationalProductsFilterCount(
|
||||
ctx context.Context,
|
||||
params ListEducationProductsParams,
|
||||
) (result ProductsFilterCount, err error)
|
||||
}
|
||||
|
||||
func NewClient(ctx context.Context, log *slog.Logger, debug bool) (c *client, err error) {
|
||||
@ -75,7 +79,12 @@ func (c *client) GetMainPageState() (*PageState, error) {
|
||||
|
||||
type ListEducationProductsParams struct {
|
||||
LearningType string
|
||||
CoursesThematics string
|
||||
CoursesThematics []string
|
||||
CourseGraphics []string
|
||||
CourseLevels []string
|
||||
CourseFormats []string
|
||||
CourseDurations []string
|
||||
CourseTypes []string
|
||||
|
||||
SortBy string
|
||||
Limit int
|
||||
@ -125,7 +134,7 @@ const (
|
||||
FilterGraphicTerm FilterGraphic = "courseTimeTermNew"
|
||||
)
|
||||
|
||||
type ListEducationProductsRequest struct {
|
||||
type listEducationProductsRequest struct {
|
||||
Fingerprint string `json:"fingerPrint,omitempty"`
|
||||
ProductName string `json:"productName,omitempty"`
|
||||
Location string `json:"location"`
|
||||
@ -163,7 +172,7 @@ type ListEducationProductsRequest struct {
|
||||
SortDirection string `json:"sortDirection"`
|
||||
}
|
||||
|
||||
type ListEducationProductsResponse struct {
|
||||
type listEducationProductsResponse struct {
|
||||
Items []Course `json:"items"`
|
||||
Organizations map[string]Organization `json:"organizations"`
|
||||
|
||||
@ -174,7 +183,7 @@ type ListEducationProductsResponse struct {
|
||||
func (c *client) ListEducationalProducts(
|
||||
ctx context.Context,
|
||||
params ListEducationProductsParams,
|
||||
) (result ListEducationProductsResponse, err error) {
|
||||
) (result listEducationProductsResponse, err error) {
|
||||
const urlPath = "/v1/education/products"
|
||||
const defaultLimit = 1
|
||||
const defaultSortProp = "advertising.position"
|
||||
@ -186,15 +195,17 @@ func (c *client) ListEducationalProducts(
|
||||
}
|
||||
|
||||
if !c.validLearningTypes.hasValue(params.LearningType) {
|
||||
return result, errors.NewValidationError("learning_type", "bad value")
|
||||
return result, errors.NewValidationError("learning_type", "unknown value")
|
||||
}
|
||||
if params.CoursesThematics != "" && !c.validCourseThematics.hasValue(params.CoursesThematics) {
|
||||
return result, errors.NewValidationError("courses_thematics", "bad value")
|
||||
for _, ct := range params.CoursesThematics {
|
||||
if !c.validCourseThematics.hasValue(ct) {
|
||||
return result, errors.NewValidationError("courses_thematics", "unknown value "+ct)
|
||||
}
|
||||
}
|
||||
|
||||
reqParams := ListEducationProductsRequest{
|
||||
reqParams := listEducationProductsRequest{
|
||||
LearningType: valueAsArray(params.LearningType),
|
||||
CoursesThematics: valueAsArray(params.CoursesThematics),
|
||||
CoursesThematics: params.CoursesThematics,
|
||||
ProductName: productName,
|
||||
Fields: defaultProductFields,
|
||||
SortProperty: defaultSortProp, // mayber sort by price?
|
||||
@ -212,12 +223,11 @@ func (c *client) ListEducationalProducts(
|
||||
Offset: params.Offset,
|
||||
}
|
||||
|
||||
req := c.http.R().
|
||||
resp, err := c.http.R().
|
||||
SetBody(reqParams).
|
||||
SetResult(&result).
|
||||
EnableTrace()
|
||||
|
||||
resp, err := req.Post(c.makeEducationURL(urlPath))
|
||||
EnableTrace().
|
||||
Post(c.makeEducationURL(urlPath))
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("making request: %w", err)
|
||||
}
|
||||
@ -229,6 +239,88 @@ func (c *client) ListEducationalProducts(
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type educationProductFilterCountRequest struct {
|
||||
Filters educationProductFilter `json:"filters"`
|
||||
}
|
||||
|
||||
type educationProductFilter struct {
|
||||
AdvertisingOnly bool `json:"advertisingOnly"`
|
||||
Location string `json:"location"`
|
||||
LearningTypes []string `json:"learningTypes"`
|
||||
CoursesThematics []string `json:"coursesThematics"`
|
||||
CourseGraphics []string `json:"courseGraphics"`
|
||||
CourseLevels []string `json:"courseLevels"`
|
||||
CourseFormats []string `json:"courseFormats"`
|
||||
CourseDurations []string `json:"courseDurations"`
|
||||
CourseTypes []string `json:"courseTypes"`
|
||||
}
|
||||
|
||||
type boolableDict map[int]int
|
||||
type nameableDict map[string]int
|
||||
|
||||
type ProductsFilterCount struct {
|
||||
IsCourseProfession boolableDict `json:"isCourseProfession"` // 0: count, 1: count eq to false + true
|
||||
CourseLevels nameableDict `json:"courseLevels"`
|
||||
CourseGraphics nameableDict `json:"courseGraphics"`
|
||||
OrganizationIDs nameableDict `json:"organizationIds"`
|
||||
HasTrialPeriod boolableDict `json:"hasTrialPeriod"`
|
||||
HasMentor boolableDict `json:"hasMentor"`
|
||||
HasJobGuarantee boolableDict `json:"hasJobGuarantee"`
|
||||
CourseFormats nameableDict `json:"courseFormats"`
|
||||
CourseDurations nameableDict `json:"courseDurations"`
|
||||
CoursesThematics nameableDict `json:"coursesThematics"`
|
||||
LearningTypes nameableDict `json:"learningTypes"`
|
||||
}
|
||||
|
||||
func (c *client) ListEducationalProductsFilterCount(
|
||||
ctx context.Context,
|
||||
params ListEducationProductsParams,
|
||||
) (result ProductsFilterCount, err error) {
|
||||
const urlPath = "/v2/education/prodicts/fitter/count"
|
||||
if err = c.checkClientInited(); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if !c.validLearningTypes.hasValue(params.LearningType) {
|
||||
return result, errors.NewValidationError("learning_type", "unknown value")
|
||||
}
|
||||
for _, ct := range params.CoursesThematics {
|
||||
if !c.validCourseThematics.hasValue(ct) {
|
||||
return result, errors.NewValidationError("courses_thematics", "unknown value "+ct)
|
||||
}
|
||||
}
|
||||
|
||||
reqParams := educationProductFilterCountRequest{
|
||||
Filters: educationProductFilter{
|
||||
AdvertisingOnly: false,
|
||||
Location: "",
|
||||
LearningTypes: valueAsArray(params.LearningType),
|
||||
CoursesThematics: params.CoursesThematics,
|
||||
CourseGraphics: params.CourseGraphics,
|
||||
CourseLevels: params.CourseLevels,
|
||||
CourseFormats: params.CourseFormats,
|
||||
CourseDurations: params.CourseDurations,
|
||||
CourseTypes: params.CourseTypes,
|
||||
},
|
||||
}
|
||||
|
||||
var respData DataContainer[ProductsFilterCount]
|
||||
resp, err := c.http.R().
|
||||
SetBody(reqParams).
|
||||
SetResult(&result).
|
||||
EnableTrace().
|
||||
Post(c.makeEducationURL(urlPath))
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("making request: %w", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
return result, fmt.Errorf("bad status code %d: %w", resp.StatusCode(), errors.ErrUnexpectedStatus)
|
||||
}
|
||||
|
||||
return respData.Data, nil
|
||||
}
|
||||
|
||||
func (c *client) makeEducationURL(path string) string {
|
||||
if c.cachedMainPageInfo == nil {
|
||||
return ""
|
||||
|
||||
@ -12,6 +12,6 @@ func (NoopClient) GetMainPageState() (*PageState, error) {
|
||||
return nil, errors.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (NoopClient) ListEducationalProducts(context.Context, ListEducationProductsParams) (ListEducationProductsResponse, error) {
|
||||
return ListEducationProductsResponse{}, errors.ErrNotImplemented
|
||||
func (NoopClient) ListEducationalProducts(context.Context, ListEducationProductsParams) (listEducationProductsResponse, error) {
|
||||
return listEducationProductsResponse{}, errors.ErrNotImplemented
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user