diff --git a/cmd/connect.go b/cmd/connect.go index ae78bd2..887f2dc 100644 --- a/cmd/connect.go +++ b/cmd/connect.go @@ -22,6 +22,12 @@ func connectBase() *cobra.Command { Use: "connect", Short: "Connect to BBS", Long: "Add a new connection to a BBS.", + PreRun: func(cmd *cobra.Command, args []string) { + sysType, _ := cmd.Flags().GetString("type") + if sysType != "hackernews" { + cmd.MarkFlagRequired("url") + } + }, Run: func(cmd *cobra.Command, args []string) { sysConfig = make(map[string]interface{}) sys, err := system.New(sysType, &sysConfig, LOG) @@ -52,7 +58,7 @@ func connectBase() *cobra.Command { &sysType, "type", "", - "Type of system to connect to (discourse, lemmy)", + "Type of system to connect to (discourse, lemmy, hackernews)", ) cmd.MarkFlagRequired("type") @@ -64,7 +70,6 @@ func connectBase() *cobra.Command { "", "URL of system (e.g. https://www.keebtalk.com)", ) - cmd.MarkFlagRequired("url") return cmd } diff --git a/system/hackernews/connect.go b/system/hackernews/connect.go new file mode 100644 index 0000000..2935b68 --- /dev/null +++ b/system/hackernews/connect.go @@ -0,0 +1,15 @@ +package hackernews + +func (sys *System) Connect(sysURL string) error { + // Credentials + credentials := make(map[string]string) + credentials["username"] = "" + credentials["password"] = "" + + if sys.config == nil { + sys.config = make(map[string]interface{}) + } + sys.config["credentials"] = credentials + + return nil +} diff --git a/system/hackernews/hackernews.go b/system/hackernews/hackernews.go new file mode 100644 index 0000000..dfceac4 --- /dev/null +++ b/system/hackernews/hackernews.go @@ -0,0 +1,151 @@ +package hackernews + +import ( + "context" + "strconv" + "time" + + hn "github.com/hermanschaaf/hackernews" + "github.com/mrusme/gobbs/models/author" + "github.com/mrusme/gobbs/models/forum" + "github.com/mrusme/gobbs/models/post" + "github.com/mrusme/gobbs/models/reply" + "github.com/mrusme/gobbs/system/adapter" + "go.uber.org/zap" +) + +type System struct { + config map[string]interface{} + logger *zap.SugaredLogger + client *hn.Client +} + +func (sys *System) GetConfig() map[string]interface{} { + return sys.config +} + +func (sys *System) SetConfig(cfg *map[string]interface{}) { + sys.config = *cfg +} + +func (sys *System) SetLogger(logger *zap.SugaredLogger) { + sys.logger = logger +} + +func (sys *System) GetCapabilities() []adapter.Capability { + var caps []adapter.Capability + + caps = append(caps, adapter.Capability{ + ID: "posts", + Name: "Posts", + }) + caps = append(caps, adapter.Capability{ + ID: "groups", + Name: "Groups", + }) + caps = append(caps, adapter.Capability{ + ID: "search", + Name: "Search", + }) + + return caps +} + +func (sys *System) Load() error { + sys.client = hn.NewClient() + return nil +} + +func (sys *System) ListPosts(sysIdx int) ([]post.Post, error) { + stories, err := sys.client.NewStories(context.Background()) + if err != nil { + return []post.Post{}, err + } + + var models []post.Post + for _, story := range stories[0:10] { + i, err := sys.client.GetItem(context.Background(), story) + if err != nil { + sys.logger.Error(err) + continue + } + + t := "post" + body := i.Text + if i.URL != "" { + t = "url" + body = i.URL + } + + createdAt := time.Unix(int64(i.Time), 0) + lastCommentedAt := createdAt + + var replies []reply.Reply + for _, commentID := range i.Kids { + replies = append(replies, reply.Reply{ + ID: strconv.Itoa(commentID), + }) + } + + models = append(models, post.Post{ + ID: strconv.Itoa(i.ID), + + Subject: i.Title, + Body: body, + + Type: t, + + Pinned: false, + Closed: i.Deleted, + + CreatedAt: createdAt, + LastCommentedAt: lastCommentedAt, + + Author: author.Author{ + ID: i.By, + Name: i.By, + }, + + Forum: forum.Forum{ + ID: "new", + Name: "New", + }, + + Replies: replies, + + SysIDX: sysIdx, + }) + } + + return models, nil +} + +func (sys *System) LoadPost(p *post.Post) error { + for r := 0; r < len(p.Replies); r++ { + reply := &p.Replies[r] + + id, err := strconv.Atoi(reply.ID) + if err != nil { + sys.logger.Error(err) + continue + } + + i, err := sys.client.GetItem(context.Background(), id) + if err != nil { + sys.logger.Error(err) + continue + } + + createdAt := time.Unix(int64(i.Time), 0) + + reply.Body = i.Text + + reply.CreatedAt = createdAt + + reply.Author = author.Author{ + ID: i.By, + Name: i.By, + } + } + return nil +} diff --git a/system/system.go b/system/system.go index 3dd495a..152432f 100644 --- a/system/system.go +++ b/system/system.go @@ -6,6 +6,7 @@ import ( "github.com/mrusme/gobbs/models/post" "github.com/mrusme/gobbs/system/adapter" "github.com/mrusme/gobbs/system/discourse" + "github.com/mrusme/gobbs/system/hackernews" "github.com/mrusme/gobbs/system/lemmy" "go.uber.org/zap" ) @@ -35,6 +36,8 @@ func New( sys = new(discourse.System) case "lemmy": sys = new(lemmy.System) + case "hackernews": + sys = new(hackernews.System) default: return nil, errors.New("No such system") }