Skip to content

Commit

Permalink
fix(yesod): add simple keyword filter
Browse files Browse the repository at this point in the history
  • Loading branch information
MuZhou233 committed Jun 30, 2024
1 parent 4c9d220 commit 0576ac4
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 61 deletions.
17 changes: 12 additions & 5 deletions app/sephirah/internal/biz/bizangela/feed.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,25 +137,32 @@ func NewFeedItemPostprocessTopic( //nolint:gocognit // TODO
for _, action := range actions.Actions {
var config modeltiphereth.FeatureRequest
err = libcodec.Unmarshal(libcodec.JSON, []byte(action.ConfigJSON), &config)
if f, ok := builtin[action.ID]; ok {
if err != nil {
return err
}
if err != nil {
return err
}
if f, ok := builtin[action.ID]; ok { //nolint:nestif // TODO
item, err = f(ctx, config, item)
if err != nil {
return err
}
if item == nil {
return nil
}
} else if a.supv.CheckFeedItemAction(action) {
var resp *porter.ExecFeedItemActionResponse
resp, err = a.porter.ExecFeedItemAction(
a.supv.CallFeedItemAction(ctx, action),
&porter.ExecFeedItemActionRequest{
Action: converter.ToPBFeatureRequest(action),
Item: converter.ToPBFeedItem(item),
})
},
)
if err != nil {
return err
}
if resp.GetItem() != nil {
return nil
}
item = converter.ToBizFeedItem(resp.GetItem())
}
}
Expand Down
46 changes: 46 additions & 0 deletions app/sephirah/internal/biz/bizyesod/builtin_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import (

"github.com/tuihub/librarian/app/sephirah/internal/model/modeltiphereth"
"github.com/tuihub/librarian/app/sephirah/internal/model/modelyesod"
"github.com/tuihub/librarian/internal/lib/libcodec"
"github.com/tuihub/librarian/internal/model/modelfeed"

"github.com/PuerkitoBio/goquery"
)

const maxImgNum = 9
const maxDescLen = 128
const simpleKeywordFilterActionID = "simple_keyword_filter"
const keywordFilterActionID = "keyword_filter"
const descriptionGeneratorActionID = "description_generator"

Expand All @@ -25,12 +27,17 @@ func GetBuiltinActionMap(
ctx context.Context,
) map[string]func(context.Context, modeltiphereth.FeatureRequest, *modelfeed.Item) (*modelfeed.Item, error) {
return map[string]func(context.Context, modeltiphereth.FeatureRequest, *modelfeed.Item) (*modelfeed.Item, error){
simpleKeywordFilterActionID: simpleKeywordFilterAction,
keywordFilterActionID: keywordFilterAction,
descriptionGeneratorActionID: descriptionGeneratorAction,
}
}

func getBuiltinActionFeatureFlags() ([]*modeltiphereth.FeatureFlag, error) {
simple, err := modelyesod.GetSimpleKeywordFilterActionConfigSchema()
if err != nil {
return nil, err
}
keyword, err := modelyesod.GetKeywordFilterActionConfigSchema()
if err != nil {
return nil, err
Expand All @@ -40,6 +47,13 @@ func getBuiltinActionFeatureFlags() ([]*modeltiphereth.FeatureFlag, error) {
return nil, err
}
return []*modeltiphereth.FeatureFlag{
{
ID: simpleKeywordFilterActionID,
Region: "",
Name: "Simple Keyword Filter",
Description: "Filter feed item by keyword",
ConfigJSONSchema: simple,
},
{
ID: keywordFilterActionID,
Region: "",
Expand Down Expand Up @@ -108,6 +122,38 @@ func parseDigestAction(_ context.Context, item *modelfeed.Item) (*modelfeed.Item
return item, nil
}

func simpleKeywordFilterAction(
_ context.Context,
request modeltiphereth.FeatureRequest,
item *modelfeed.Item,
) (*modelfeed.Item, error) {
config := new(modelyesod.SimpleKeywordFilterActionConfig)
if err := libcodec.Unmarshal(libcodec.JSON, []byte(request.ConfigJSON), config); err != nil {
return nil, err
}
for _, titleInclude := range config.TitleInclude {
if !strings.Contains(item.Title, titleInclude) {
return nil, nil //nolint:nilnil // return nil to skip this item
}
}
for _, titleExclude := range config.TitleExclude {
if strings.Contains(item.Title, titleExclude) {
return nil, nil //nolint:nilnil // return nil to skip this item
}
}
for _, contentInclude := range config.ContentInclude {
if !strings.Contains(item.Content, contentInclude) {
return nil, nil //nolint:nilnil // return nil to skip this item
}
}
for _, contentExclude := range config.ContentExclude {
if strings.Contains(item.Content, contentExclude) {
return nil, nil //nolint:nilnil // return nil to skip this item
}
}
return item, nil
}

func keywordFilterAction(ctx context.Context, _ modeltiphereth.FeatureRequest, item *modelfeed.Item) (*modelfeed.Item, error) {
// TODO: impl
return item, nil
Expand Down
6 changes: 6 additions & 0 deletions app/sephirah/internal/biz/bizyesod/feed_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ func (y *Yesod) CreateFeedActionSet(
if claims == nil {
return 0, bizutils.NoPermissionError()
}
if len(set.Actions) == 0 {
return 0, pb.ErrorErrorReasonBadRequest("actions is empty")
}
id, err := y.searcher.NewID(ctx)
if err != nil {
return 0, pb.ErrorErrorReasonUnspecified("%s", err.Error())
Expand All @@ -37,6 +40,9 @@ func (y *Yesod) UpdateFeedActionSet(ctx context.Context, set *modelyesod.FeedAct
if claims == nil {
return bizutils.NoPermissionError()
}
if len(set.Actions) == 0 {
return pb.ErrorErrorReasonBadRequest("actions is empty")
}
err := y.repo.UpdateFeedActionSet(ctx, claims.UserID, set)
if err != nil {
return pb.ErrorErrorReasonUnspecified("%s", err.Error())
Expand Down
126 changes: 79 additions & 47 deletions app/sephirah/internal/data/yesod.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,55 +32,80 @@ func NewYesodRepo(data *Data) bizyesod.YesodRepo {
}

func (y *yesodRepo) CreateFeedConfig(ctx context.Context, owner model.InternalID, c *modelyesod.FeedConfig) error {
q := y.data.db.FeedConfig.Create().
SetOwnerID(owner).
SetID(c.ID).
SetName(c.Name).
SetFeedURL(c.FeedURL).
SetCategory(c.Category).
SetAuthorAccount(c.AuthorAccount).
SetSource(c.Source).
SetStatus(converter.ToEntFeedConfigStatus(c.Status)).
SetPullInterval(c.PullInterval).
SetLatestPullStatus(converter.ToEntFeedConfigLatestPullStatus(c.LatestPullStatus)).
SetLatestPullMessage("").
SetHideItems(c.HideItems).
AddFeedActionSetIDs(c.ActionSets...)
return q.Exec(ctx)
return y.data.WithTx(ctx, func(tx *ent.Tx) error {
err := tx.FeedConfig.Create().
SetOwnerID(owner).
SetID(c.ID).
SetName(c.Name).
SetFeedURL(c.FeedURL).
SetCategory(c.Category).
SetAuthorAccount(c.AuthorAccount).
SetSource(c.Source).
SetStatus(converter.ToEntFeedConfigStatus(c.Status)).
SetPullInterval(c.PullInterval).
SetLatestPullStatus(converter.ToEntFeedConfigLatestPullStatus(c.LatestPullStatus)).
SetLatestPullMessage("").
SetHideItems(c.HideItems).
Exec(ctx)
if err != nil {
return err
}
actionCreate := make([]*ent.FeedConfigActionCreate, len(c.ActionSets))
for i, action := range c.ActionSets {
actionCreate[i] = tx.FeedConfigAction.Create().
SetFeedConfigID(c.ID).
SetFeedActionSetID(action).
SetIndex(int64(i))
}
return tx.FeedConfigAction.CreateBulk(actionCreate...).Exec(ctx)
})
}

func (y *yesodRepo) UpdateFeedConfig(ctx context.Context, userID model.InternalID, c *modelyesod.FeedConfig) error {
q := y.data.db.FeedConfig.Update().
Where(
feedconfig.IDEQ(c.ID),
feedconfig.HasOwnerWith(user.IDEQ(userID)),
)
if len(c.Name) > 0 {
q.SetName(c.Name)
}
if len(c.FeedURL) > 0 {
q.SetFeedURL(c.FeedURL)
}
if len(c.Category) > 0 {
q.SetCategory(c.Category)
}
if c.AuthorAccount > 0 {
q.SetAuthorAccount(c.AuthorAccount)
}
if len(c.Source) > 0 {
q.SetSource(c.Source)
}
if c.Status != modelyesod.FeedConfigStatusUnspecified {
q.SetStatus(converter.ToEntFeedConfigStatus(c.Status))
}
if c.PullInterval > 0 {
q.SetPullInterval(c.PullInterval).SetNextPullBeginAt(time.Now())
}
if c.ActionSets != nil {
q.ClearFeedActionSet().AddFeedActionSetIDs(c.ActionSets...)
}
q.SetHideItems(c.HideItems)
return q.Exec(ctx)
return y.data.WithTx(ctx, func(tx *ent.Tx) error {
q := tx.FeedConfig.Update().
Where(
feedconfig.IDEQ(c.ID),
feedconfig.HasOwnerWith(user.IDEQ(userID)),
)
if len(c.Name) > 0 {
q.SetName(c.Name)
}
if len(c.FeedURL) > 0 {
q.SetFeedURL(c.FeedURL)
}
if len(c.Category) > 0 {
q.SetCategory(c.Category)
}
if c.AuthorAccount > 0 {
q.SetAuthorAccount(c.AuthorAccount)
}
if len(c.Source) > 0 {
q.SetSource(c.Source)
}
if c.Status != modelyesod.FeedConfigStatusUnspecified {
q.SetStatus(converter.ToEntFeedConfigStatus(c.Status))
}
if c.PullInterval > 0 {
q.SetPullInterval(c.PullInterval).SetNextPullBeginAt(time.Now())
}
if c.ActionSets != nil {
q.ClearFeedActionSet()
}
q.SetHideItems(c.HideItems)
err := q.Exec(ctx)
if err != nil {
return err
}
actionCreate := make([]*ent.FeedConfigActionCreate, len(c.ActionSets))
for i, action := range c.ActionSets {
actionCreate[i] = tx.FeedConfigAction.Create().
SetFeedConfigID(c.ID).
SetFeedActionSetID(action).
SetIndex(int64(i))
}
return tx.FeedConfigAction.CreateBulk(actionCreate...).Exec(ctx)
})
}

// UpdateFeedConfigAsInQueue set SetNextPullBeginAt to one day later to avoid repeat queue.
Expand Down Expand Up @@ -117,7 +142,7 @@ func (y *yesodRepo) ListFeedConfigNeedPull(ctx context.Context, sources []string
return converter.ToBizFeedConfigList(feedConfigs), nil
}

func (y *yesodRepo) ListFeedConfigs(
func (y *yesodRepo) ListFeedConfigs( //nolint:gocognit //TODO
ctx context.Context,
userID model.InternalID,
paging model.Paging,
Expand Down Expand Up @@ -158,12 +183,19 @@ func (y *yesodRepo) ListFeedConfigs(
Limit(paging.ToLimit()).
Offset(paging.ToOffset()).
WithFeed().
WithFeedActionSet().
All(ctx)
if err != nil {
return err
}
res = make([]*modelyesod.FeedWithConfig, 0, len(configs))
for _, config := range configs {
feedConfig := converter.ToBizFeedConfig(config)
actionSets := make([]model.InternalID, 0, len(config.Edges.FeedActionSet))
for _, actionSet := range config.Edges.FeedActionSet {
actionSets = append(actionSets, actionSet.ID)
}
feedConfig.ActionSets = actionSets
res = append(res, &modelyesod.FeedWithConfig{
FeedConfig: converter.ToBizFeedConfig(config),
Feed: converter.ToBizFeed(config.Edges.Feed),
Expand Down
26 changes: 17 additions & 9 deletions app/sephirah/internal/model/modelyesod/builtin_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@ package modelyesod

import "github.com/invopop/jsonschema"

type SimpleKeywordFilterActionConfig struct {
TitleInclude []string `json:"title_include" jsonschema:"title=Title include"`
TitleExclude []string `json:"title_exclude" jsonschema:"title=Title exclude"`
ContentInclude []string `json:"content_include" jsonschema:"title=Content include"`
ContentExclude []string `json:"content_exclude" jsonschema:"title=Content exclude"`
}

func GetSimpleKeywordFilterActionConfigSchema() (string, error) {
return reflectJSONSchema(new(SimpleKeywordFilterActionConfig))
}

type KeywordFilterActionConfig struct {
OrList []*KeywordFilterAndList `json:"or_list" jsonschema:"title=OR list"`
}

func GetKeywordFilterActionConfigSchema() (string, error) {
r := new(jsonschema.Reflector)
r.ExpandedStruct = true
r.DoNotReference = true
j, err := r.Reflect(new(KeywordFilterActionConfig)).MarshalJSON()
if err != nil {
return "", err
}
return string(j), nil
return reflectJSONSchema(new(KeywordFilterActionConfig))
}

type KeywordFilterAndList struct {
Expand Down Expand Up @@ -52,10 +56,14 @@ const (
type DescriptionGeneratorActionConfig struct{}

func GetDescriptionGeneratorActionConfigSchema() (string, error) {
return reflectJSONSchema(new(DescriptionGeneratorActionConfig))
}

func reflectJSONSchema(v interface{}) (string, error) {
r := new(jsonschema.Reflector)
r.ExpandedStruct = true
r.DoNotReference = true
j, err := r.Reflect(new(DescriptionGeneratorActionConfig)).MarshalJSON()
j, err := r.Reflect(v).MarshalJSON()
if err != nil {
return "", err
}
Expand Down
8 changes: 8 additions & 0 deletions app/sephirah/internal/model/modelyesod/builtin_action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ import (
"github.com/tuihub/librarian/app/sephirah/internal/model/modelyesod"
)

func TestGetSimpleKeywordFilterActionConfigSchema(t *testing.T) {
s, err := modelyesod.GetSimpleKeywordFilterActionConfigSchema()
t.Log(s)
if err != nil {
t.Errorf("GetSimpleKeywordFilterActionConfigSchema() error = %v", err)
}
}

func TestGetKeywordFilterActionConfigSchema(t *testing.T) {
s, err := modelyesod.GetKeywordFilterActionConfigSchema()
t.Log(s)
Expand Down

0 comments on commit 0576ac4

Please sign in to comment.