mirror of
https://github.com/mrusme/neonmodem.git
synced 2024-12-04 14:46:37 -05:00
Extended discourse implementation
This commit is contained in:
parent
49205c4b7f
commit
a34fa46c3d
200
system/discourse/client.go
Normal file
200
system/discourse/client.go
Normal file
@ -0,0 +1,200 @@
|
||||
package discourse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
Type string `json:"type"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Message string `json:"message"`
|
||||
Validation map[string]interface{} `json:"validation,omitempty"`
|
||||
|
||||
Post PostModel `json:"post,omitempty"`
|
||||
Posts []PostModel `json:"latest_posts,omitempty"`
|
||||
}
|
||||
|
||||
type RequestError struct {
|
||||
Response Response
|
||||
Err error
|
||||
}
|
||||
|
||||
func (re *RequestError) Error() string {
|
||||
return re.Err.Error()
|
||||
}
|
||||
|
||||
func (re *RequestError) Type() string {
|
||||
return re.Response.Type
|
||||
}
|
||||
|
||||
func (re *RequestError) Message() string {
|
||||
return re.Response.Message
|
||||
}
|
||||
|
||||
type Logger interface {
|
||||
Debug(args ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
|
||||
Info(args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
|
||||
Warn(args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
|
||||
Error(args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
type StdLogger struct {
|
||||
L Logger
|
||||
}
|
||||
|
||||
func NewStdLogger(l Logger) retryablehttp.Logger {
|
||||
return &StdLogger{
|
||||
L: l,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *StdLogger) Printf(message string, v ...interface{}) {
|
||||
l.L.Debug(message, v)
|
||||
}
|
||||
|
||||
type ClientConfig struct {
|
||||
Endpoint string
|
||||
Credentials map[string]string
|
||||
HTTPClient *http.Client
|
||||
Logger Logger
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
httpClient *retryablehttp.Client
|
||||
endpoint *url.URL
|
||||
credentials map[string]string
|
||||
logger Logger
|
||||
Posts PostsService
|
||||
}
|
||||
|
||||
func NewDefaultClientConfig(
|
||||
endpoint string,
|
||||
credentials map[string]string,
|
||||
logger Logger,
|
||||
) ClientConfig {
|
||||
return ClientConfig{
|
||||
Endpoint: endpoint,
|
||||
Credentials: credentials,
|
||||
HTTPClient: http.DefaultClient,
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func NewClient(cc *ClientConfig) *Client {
|
||||
c := new(Client)
|
||||
c.logger = cc.Logger
|
||||
c.httpClient = retryablehttp.NewClient()
|
||||
c.httpClient.RetryMax = 3
|
||||
if c.logger != nil {
|
||||
c.httpClient.Logger = NewStdLogger(c.logger)
|
||||
}
|
||||
c.httpClient.HTTPClient = cc.HTTPClient
|
||||
c.endpoint, _ = url.Parse(cc.Endpoint)
|
||||
c.credentials = cc.Credentials
|
||||
fmt.Printf("%v\n", c.credentials)
|
||||
|
||||
c.Posts = &PostServiceHandler{client: c}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) NewRequest(
|
||||
ctx context.Context,
|
||||
method string,
|
||||
location string,
|
||||
body interface{},
|
||||
) (*http.Request, error) {
|
||||
var parsedURL *url.URL
|
||||
var req *http.Request
|
||||
var err error
|
||||
|
||||
if parsedURL, err = c.endpoint.Parse(location); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buffer := new(bytes.Buffer)
|
||||
if body != nil {
|
||||
if err = json.NewEncoder(buffer).Encode(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if req, err = http.NewRequest(
|
||||
method,
|
||||
parsedURL.String(),
|
||||
buffer,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("User-Agent", "gobbs")
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("Api-Username", c.credentials["username"])
|
||||
req.Header.Add("Api-Key", c.credentials["key"])
|
||||
|
||||
fmt.Printf("%v\n", req)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) Do(
|
||||
ctx context.Context,
|
||||
req *http.Request,
|
||||
content *Response,
|
||||
) error {
|
||||
var rreq *retryablehttp.Request
|
||||
var res *http.Response
|
||||
var body []byte
|
||||
var err error
|
||||
|
||||
if rreq, err = retryablehttp.FromRequest(req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rreq = rreq.WithContext(ctx)
|
||||
if res, err = c.httpClient.Do(rreq); err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if body, err = ioutil.ReadAll(res.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if content != nil {
|
||||
if err = json.Unmarshal(body, content); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%v\n", res)
|
||||
|
||||
if res.StatusCode < http.StatusOK ||
|
||||
res.StatusCode > http.StatusNoContent {
|
||||
return &RequestError{
|
||||
Err: errors.New("Non-2xx status code"),
|
||||
Response: *content,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -2,6 +2,7 @@ package discourse
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
@ -9,6 +10,7 @@ import (
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
@ -17,10 +19,12 @@ import (
|
||||
"github.com/mrusme/gobbs/models/post"
|
||||
"github.com/mrusme/gobbs/system/adapter"
|
||||
"github.com/pkg/browser"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type System struct {
|
||||
config map[string]interface{}
|
||||
logger *zap.SugaredLogger
|
||||
}
|
||||
|
||||
type UserAPIKey struct {
|
||||
@ -38,6 +42,10 @@ func (sys *System) SetConfig(cfg *map[string]interface{}) {
|
||||
sys.config = *cfg
|
||||
}
|
||||
|
||||
func (sys *System) SetLogger(logger *zap.SugaredLogger) {
|
||||
sys.logger = logger
|
||||
}
|
||||
|
||||
func (sys *System) Load() error {
|
||||
|
||||
return nil
|
||||
@ -149,12 +157,31 @@ func (sys *System) Connect(sysURL string) error {
|
||||
if sys.config == nil {
|
||||
sys.config = make(map[string]interface{})
|
||||
}
|
||||
sys.config["url"] = sysURL
|
||||
sys.config["credentials"] = credentials
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sys *System) ListPosts() ([]post.Post, error) {
|
||||
credentials := make(map[string]string)
|
||||
for k, v := range (sys.config["credentials"]).(map[string]interface{}) {
|
||||
credentials[k] = v.(string)
|
||||
}
|
||||
c := NewClient(&ClientConfig{
|
||||
Endpoint: sys.config["url"].(string),
|
||||
Credentials: credentials,
|
||||
HTTPClient: http.DefaultClient,
|
||||
Logger: sys.logger,
|
||||
})
|
||||
|
||||
posts, err := c.Posts.List(context.Background())
|
||||
if err != nil {
|
||||
return []post.Post{}, err
|
||||
}
|
||||
|
||||
fmt.Printf("%v\n", posts)
|
||||
|
||||
return []post.Post{}, nil
|
||||
}
|
||||
|
||||
|
115
system/discourse/posts.go
Normal file
115
system/discourse/posts.go
Normal file
@ -0,0 +1,115 @@
|
||||
package discourse
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const PostsBaseURL = "/posts"
|
||||
|
||||
type PostModel struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
AvatarTemplate string `json:"avater_template"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Cooked string `json:"cooked"`
|
||||
PostNumber int `json:"post_number"`
|
||||
PostType int `json:"post_type"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
ReplyCount int `json:"reply_count"`
|
||||
IncomingLinkCount int `json:"incoming_link_count"`
|
||||
Reads int `json:"reads"`
|
||||
ReadersCount int `json:"readers_count"`
|
||||
Score int `json:"score"`
|
||||
Yours bool `json:"yours"`
|
||||
TopicID int `json:"topic_id"`
|
||||
TopicSlug string `json:"topic_slug"`
|
||||
TopicTitle string `json:"topic_title"`
|
||||
TopicHTMLTitle string `json:"topic_html_title"`
|
||||
CategoryID int `json:"category_id"`
|
||||
DisplayUsername string `json:"display_username"`
|
||||
PrimaryGroupName string `json:"primary_group_name"`
|
||||
FlairName string `json:"flair_name"`
|
||||
FlairURL string `json:"flair_url"`
|
||||
FlairBGColor string `json:"flair_bg_color"`
|
||||
FlairColor string `json:"flair_color"`
|
||||
Version int `json:"version"`
|
||||
CanEdit bool `json:"can_edit"`
|
||||
CanDelete bool `json:"can_delete"`
|
||||
CanRecover bool `json:"can_recover"`
|
||||
CanWiki bool `json:"can_wiki"`
|
||||
UserTitle string `json:"user_title"`
|
||||
Raw string `json:"raw"`
|
||||
ActionsSummary struct {
|
||||
ID int `json:"id"`
|
||||
CanAct bool `json:"can_act"`
|
||||
} `json:"actions_summary"`
|
||||
Moderator bool `json:"moderator"`
|
||||
Admin bool `json:"admin"`
|
||||
Staff bool `json:"staff"`
|
||||
UserID int `json:"user_id"`
|
||||
Hidden bool `json:"hidden"`
|
||||
TrustLevel int `json:"trust_level"`
|
||||
DeletedAt string `json:"deleted_at"`
|
||||
UserDeleted bool `json:"user_deleted"`
|
||||
EditReason string `json:"edit_reason"`
|
||||
CanViewEditHistory bool `json:"can_view_edit_history"`
|
||||
Wiki bool `json:"wiki"`
|
||||
ReviewableID string `json:"reviewable_id"`
|
||||
ReviewableScoreCount int `json:"reviewable_score_count"`
|
||||
ReviewableScorePendingCount int `json:"reviewable_score_pending_count"`
|
||||
}
|
||||
|
||||
type PostsService interface {
|
||||
Show(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
) (PostModel, error)
|
||||
List(
|
||||
ctx context.Context,
|
||||
) ([]PostModel, error)
|
||||
}
|
||||
|
||||
type PostServiceHandler struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Show
|
||||
func (a *PostServiceHandler) Show(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
) (PostModel, error) {
|
||||
uri := PostsBaseURL + "/" + id + ".json"
|
||||
|
||||
req, err := a.client.NewRequest(ctx, http.MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return PostModel{}, err
|
||||
}
|
||||
|
||||
response := new(Response)
|
||||
if err = a.client.Do(ctx, req, response); err != nil {
|
||||
return PostModel{}, err
|
||||
}
|
||||
|
||||
return response.Post, nil
|
||||
}
|
||||
|
||||
// List
|
||||
func (a *PostServiceHandler) List(
|
||||
ctx context.Context,
|
||||
) ([]PostModel, error) {
|
||||
uri := PostsBaseURL + ".json"
|
||||
|
||||
req, err := a.client.NewRequest(ctx, http.MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return []PostModel{}, err
|
||||
}
|
||||
|
||||
response := new(Response)
|
||||
if err = a.client.Do(ctx, req, response); err != nil {
|
||||
return []PostModel{}, err
|
||||
}
|
||||
|
||||
return response.Posts, nil
|
||||
}
|
@ -3,10 +3,12 @@ package lemmy
|
||||
import (
|
||||
"github.com/mrusme/gobbs/models/post"
|
||||
"github.com/mrusme/gobbs/system/adapter"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type System struct {
|
||||
config map[string]interface{}
|
||||
logger *zap.SugaredLogger
|
||||
}
|
||||
|
||||
func (sys *System) GetConfig() map[string]interface{} {
|
||||
@ -17,6 +19,10 @@ func (sys *System) SetConfig(cfg *map[string]interface{}) {
|
||||
sys.config = *cfg
|
||||
}
|
||||
|
||||
func (sys *System) SetLogger(logger *zap.SugaredLogger) {
|
||||
sys.logger = logger
|
||||
}
|
||||
|
||||
func (sys *System) Connect(sysURL string) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -7,11 +7,13 @@ import (
|
||||
"github.com/mrusme/gobbs/system/adapter"
|
||||
"github.com/mrusme/gobbs/system/discourse"
|
||||
"github.com/mrusme/gobbs/system/lemmy"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type System interface {
|
||||
GetConfig() map[string]interface{}
|
||||
SetConfig(cfg *map[string]interface{})
|
||||
SetLogger(logger *zap.SugaredLogger)
|
||||
GetCapabilities() []adapter.Capability
|
||||
|
||||
Connect(sysURL string) error
|
||||
@ -20,7 +22,11 @@ type System interface {
|
||||
ListPosts() ([]post.Post, error)
|
||||
}
|
||||
|
||||
func New(sysType string, sysConfig *map[string]interface{}) (System, error) {
|
||||
func New(
|
||||
sysType string,
|
||||
sysConfig *map[string]interface{},
|
||||
logger *zap.SugaredLogger,
|
||||
) (System, error) {
|
||||
var sys System
|
||||
|
||||
switch sysType {
|
||||
@ -33,6 +39,7 @@ func New(sysType string, sysConfig *map[string]interface{}) (System, error) {
|
||||
}
|
||||
|
||||
sys.SetConfig(sysConfig)
|
||||
sys.SetLogger(logger)
|
||||
err := sys.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
Loading…
Reference in New Issue
Block a user