package main import ( "context" "fmt" "log/slog" "strconv" "strings" "git.loyso.art/frx/kurious/internal/common/client/sravni" "git.loyso.art/frx/kurious/internal/common/errors" "git.loyso.art/frx/kurious/internal/common/xslices" "github.com/teris-io/cli" ) const ( learningTypeOptName = "learning-type" courseThematicOptName = "course-thematic" learningTypeSelectionOptName = "learning-selection" ) func setupAPICommand(ctx context.Context) cli.Command { learningTypeOpt := cli.NewOption(learningTypeOptName, "Specify learning type"). WithType(cli.TypeString) courseThematic := cli.NewOption(courseThematicOptName, "Specify course thematic"). WithType(cli.TypeString) learningSelectionOpt := cli.NewOption(learningTypeSelectionOptName, "Specify learning type selection"). WithType(cli.TypeString) apiEducationListProducts := buildCLICommand(func() cli.Command { return cli.NewCommand("list_products", "List products by some filters"). WithOption(learningTypeOpt). WithOption(courseThematic). WithOption(learningSelectionOpt). WithOption(limitOption). 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(apiEducationFilterCount) return cli.NewCommand("api", "Interaction with API"). WithCommand(apiEducation) } type action interface { context() context.Context parse(args []string, options map[string]string) error handle() error } func asCLIAction(a action) cli.Action { return func(args []string, options map[string]string) int { ctx := a.context() log := makeLogger(options) err := a.parse(args, options) if err != nil { log.ErrorContext(ctx, "unable to parse args and opts", slog.Any("err", err)) return -1 } err = a.handle() if err != nil { log.ErrorContext(ctx, "unable to handle action", slog.Any("err", err)) return -1 } return 0 } } type listProductsActionParams struct { learningType string courseThematic string learningSelectionType string limit int offset int } type listProductsAction struct { *baseAction client sravni.Client params listProductsActionParams } func newListProductAction(ctx context.Context) cli.Action { action := &listProductsAction{ baseAction: newBaseAction(ctx), } return asCLIAction(action) } func (a *listProductsAction) 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 = options[courseThematicOptName] a.params.learningSelectionType = options[learningTypeSelectionOptName] if value, ok := options[limitOption.Key()]; ok { a.params.limit, _ = strconv.Atoi(value) } if value, ok := options[offsetOption.Key()]; ok { a.params.offset, _ = strconv.Atoi(value) } 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 *listProductsAction) handle() error { params := sravni.ListEducationProductsParams{ LearningType: a.params.learningType, CoursesThematics: []string{a.params.courseThematic}, Limit: a.params.limit, Offset: a.params.offset, } result, err := a.client.ListEducationalProducts(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 } 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") } filterNotEmpty := func(value string) bool { return value != "" } a.params.courseThematic = xslices.Filter( strings.Split(options[courseThematicOptName], ","), filterNotEmpty, ) 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 }