mirror of https://gitlab.com/ngerakines/tavern.git
parent
99a00f5024
commit
64875a799c
|
@ -0,0 +1,58 @@
|
|||
package avatar
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/teacat/noire"
|
||||
)
|
||||
|
||||
const avatarSVG = `<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="$WIDTH" height="$HEIGHT" viewBox="0 0 $WIDTH $HEIGHT" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="$FIRST"/>
|
||||
<stop offset="100%" stop-color="$SECOND"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect fill="url(#bg)" x="0" y="0" width="$WIDTH" height="$HEIGHT"/>
|
||||
</g>
|
||||
</svg>
|
||||
`
|
||||
|
||||
func AvatarSVG(input string, size int) string {
|
||||
primary := toColor(input)
|
||||
secondary := fmt.Sprintf("#%s", noire.NewHex(primary).Complement().Hex())
|
||||
|
||||
height := size
|
||||
width := size
|
||||
r := strings.NewReplacer(
|
||||
"$FIRST", primary,
|
||||
"$SECOND", fmt.Sprintf("#%s", secondary),
|
||||
"$WIDTH", strconv.Itoa(width),
|
||||
"$HEIGHT", strconv.Itoa(height),
|
||||
)
|
||||
return r.Replace(avatarSVG)
|
||||
}
|
||||
|
||||
func djb2(data []byte) int32 {
|
||||
var h int32 = 5381
|
||||
for _, b := range data {
|
||||
h = (h << 5) + h + int32(b)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func toColor(input string) string {
|
||||
mh := md5.New()
|
||||
mh.Write([]byte(input))
|
||||
h := djb2(mh.Sum(nil))
|
||||
r := (h & 0xff0000) >> 16
|
||||
g := (h & 0x00ff00) >> 8
|
||||
b := h & 0x0000ff
|
||||
return fmt.Sprintf("#%02x%02x%02x", r, g, b)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// HTTPClient provides the http.Do function in a generic way.
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// DefaultHTTPClient returns an HTTPClient with a reasonable default timeout.
|
||||
func DefaultHTTPClient() HTTPClient {
|
||||
return &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type NoOpReaderCloser struct {
|
||||
Reader io.Reader
|
||||
}
|
||||
|
||||
func (rc NoOpReaderCloser) Read(p []byte) (n int, err error) {
|
||||
return rc.Reader.Read(p)
|
||||
}
|
||||
|
||||
func (rc NoOpReaderCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ io.ReadCloser = NoOpReaderCloser{}
|
|
@ -0,0 +1,31 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var EnableSVGerFlag = cli.BoolFlag{
|
||||
Name: "enable-svger",
|
||||
Usage: "Enable svger integration",
|
||||
EnvVars: []string{"ENABLE_SVGER"},
|
||||
Value: false,
|
||||
}
|
||||
|
||||
var SVGerEndpointFlag = cli.StringFlag{
|
||||
Name: "svger",
|
||||
Usage: "The SVGer to interact with.",
|
||||
EnvVars: []string{"SVGER",},
|
||||
Value: "http://localhost:5003/",
|
||||
}
|
||||
|
||||
type SVGerConfig struct {
|
||||
Enabled bool
|
||||
Location string
|
||||
}
|
||||
|
||||
func NewSVGerConfig(cliCtx *cli.Context) SVGerConfig {
|
||||
return SVGerConfig{
|
||||
Enabled: cliCtx.Bool("enable-svger"),
|
||||
Location: cliCtx.String("svger"),
|
||||
}
|
||||
}
|
|
@ -11,12 +11,13 @@ import (
|
|||
"github.com/yukimochi/httpsig"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/g"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
)
|
||||
|
||||
type ActivityClient struct {
|
||||
HTTPClient HTTPClient
|
||||
HTTPClient common.HTTPClient
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
|
@ -43,7 +44,7 @@ func (client ActivityClient) GetSigned(location string, localActor storage.Local
|
|||
return ldJsonGetSigned(client.HTTPClient, location, signer, localActor.GetKeyID(), privateKey)
|
||||
}
|
||||
|
||||
func ldJsonGet(client HTTPClient, location string) (string, storage.Payload, error) {
|
||||
func ldJsonGet(client common.HTTPClient, location string) (string, storage.Payload, error) {
|
||||
request, err := http.NewRequest("GET", location, nil)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
|
@ -73,7 +74,7 @@ func ldJsonGet(client HTTPClient, location string) (string, storage.Payload, err
|
|||
return string(body), p, nil
|
||||
}
|
||||
|
||||
func ldJsonGetSigned(client HTTPClient, location string, signer httpsig.Signer, keyID string, privateKey *rsa.PrivateKey) (string, storage.Payload, error) {
|
||||
func ldJsonGetSigned(client common.HTTPClient, location string, signer httpsig.Signer, keyID string, privateKey *rsa.PrivateKey) (string, storage.Payload, error) {
|
||||
request, err := http.NewRequest("GET", location, nil)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
|
|
|
@ -10,11 +10,12 @@ import (
|
|||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
)
|
||||
|
||||
type ActorClient struct {
|
||||
HTTPClient HTTPClient
|
||||
HTTPClient common.HTTPClient
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
|
@ -49,7 +50,7 @@ func (client ActorClient) Get(location string) (string, storage.Payload, error)
|
|||
return string(body), p, nil
|
||||
}
|
||||
|
||||
func GetOrFetchActor(ctx context.Context, store storage.Storage, logger *zap.Logger, httpClient HTTPClient, hint string) (storage.Actor, error) {
|
||||
func GetOrFetchActor(ctx context.Context, store storage.Storage, logger *zap.Logger, httpClient common.HTTPClient, hint string) (storage.Actor, error) {
|
||||
var actorURL string
|
||||
if strings.HasPrefix(hint, "https://") {
|
||||
actorURL = hint
|
||||
|
|
|
@ -7,11 +7,12 @@ import (
|
|||
"github.com/yukimochi/httpsig"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
)
|
||||
|
||||
type Crawler struct {
|
||||
HTTPClient HTTPClient
|
||||
HTTPClient common.HTTPClient
|
||||
Logger *zap.Logger
|
||||
Storage storage.Storage
|
||||
MaxDepth int
|
||||
|
|
|
@ -2,21 +2,17 @@ package fed
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
)
|
||||
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
type WebFingerClient struct {
|
||||
HTTPClient HTTPClient
|
||||
HTTPClient common.HTTPClient
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -14,11 +14,13 @@ require (
|
|||
github.com/gofrs/uuid v3.2.0+incompatible
|
||||
github.com/kr/pretty v0.1.0
|
||||
github.com/lib/pq v1.3.0
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3
|
||||
github.com/microcosm-cc/bluemonday v1.0.2
|
||||
github.com/oklog/run v1.0.0
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sslhound/herr v1.4.1 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/teacat/noire v1.0.0
|
||||
github.com/urfave/cli/v2 v2.1.1
|
||||
github.com/yukimochi/httpsig v0.1.3
|
||||
go.uber.org/zap v1.13.0
|
||||
|
|
4
go.sum
4
go.sum
|
@ -130,6 +130,8 @@ github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
|||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
|
@ -196,6 +198,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/teacat/noire v1.0.0 h1:+s/oXhDE+HuBUgObpjO3dHEPupo5yiLiUg+7/R6FmYk=
|
||||
github.com/teacat/noire v1.0.0/go.mod h1:7FDkAv8Eaxqg/9rbSgACb/fVNsTM9khy+rFC6pcnXEE=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/gofrs/uuid"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/fed"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
)
|
||||
|
@ -19,7 +20,7 @@ type crawl struct {
|
|||
logger *zap.Logger
|
||||
queue storage.StringQueue
|
||||
storage storage.Storage
|
||||
httpClient HTTPClient
|
||||
httpClient common.HTTPClient
|
||||
}
|
||||
|
||||
func NewCrawlWorker(logger *zap.Logger, queue storage.StringQueue, storage storage.Storage) Job {
|
||||
|
@ -27,7 +28,7 @@ func NewCrawlWorker(logger *zap.Logger, queue storage.StringQueue, storage stora
|
|||
logger: logger,
|
||||
queue: queue,
|
||||
storage: storage,
|
||||
httpClient: DefaultHTTPClient(),
|
||||
httpClient: common.DefaultHTTPClient(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +84,7 @@ func (job *crawl) work() error {
|
|||
}
|
||||
|
||||
crawler := &fed.Crawler{
|
||||
HTTPClient: DefaultHTTPClient(),
|
||||
HTTPClient: job.httpClient,
|
||||
Logger: job.logger,
|
||||
Storage: job.storage,
|
||||
MaxDepth: fed.CrawlerDefaultMaxCount,
|
||||
|
|
12
job/http.go
12
job/http.go
|
@ -1,12 +0,0 @@
|
|||
package job
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func DefaultHTTPClient() HTTPClient {
|
||||
return &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
}
|
|
@ -2,17 +2,12 @@ package job
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/oklog/run"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
type Job interface {
|
||||
Run(context.Context) error
|
||||
Shutdown(context.Context) error
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/fed"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
)
|
||||
|
@ -17,7 +18,7 @@ type webfinger struct {
|
|||
logger *zap.Logger
|
||||
queue storage.StringQueue
|
||||
storage storage.Storage
|
||||
httpClient HTTPClient
|
||||
httpClient common.HTTPClient
|
||||
}
|
||||
|
||||
func NewWebFingerWorker(logger *zap.Logger, queue storage.StringQueue, storage storage.Storage) Job {
|
||||
|
@ -25,7 +26,7 @@ func NewWebFingerWorker(logger *zap.Logger, queue storage.StringQueue, storage s
|
|||
logger: logger,
|
||||
queue: queue,
|
||||
storage: storage,
|
||||
httpClient: DefaultHTTPClient(),
|
||||
httpClient: common.DefaultHTTPClient(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ var Command = cli.Command{
|
|||
EnvVars: []string{"ADMIN_NAME"},
|
||||
Value: "nick",
|
||||
},
|
||||
&config.EnableSVGerFlag,
|
||||
&config.SVGerEndpointFlag,
|
||||
},
|
||||
Action: serverCommandAction,
|
||||
}
|
||||
|
@ -76,6 +78,7 @@ func serverCommandAction(cliCtx *cli.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
svgerConfig := config.NewSVGerConfig(cliCtx)
|
||||
|
||||
if sentryConfig.Enabled {
|
||||
err = sentry.Init(sentry.ClientOptions{
|
||||
|
@ -171,6 +174,11 @@ func serverCommandAction(cliCtx *cli.Context) error {
|
|||
webFingerQueue := storage.NewStringQueue()
|
||||
crawlQueue := storage.NewStringQueue()
|
||||
|
||||
var svgConv SVGConverter
|
||||
if svgerConfig.Enabled {
|
||||
svgConv = DefaultSVGerClient(svgerConfig.Location)
|
||||
}
|
||||
|
||||
h := handler{
|
||||
storage: s,
|
||||
logger: logger,
|
||||
|
@ -180,6 +188,7 @@ func serverCommandAction(cliCtx *cli.Context) error {
|
|||
crawlQueue: crawlQueue,
|
||||
adminUser: cliCtx.String("admin-name"),
|
||||
url: tmplUrlGen(siteBase),
|
||||
svgConverter: svgConv,
|
||||
}
|
||||
|
||||
configI18nMiddleware(sentryConfig, logger, utrans, domain, r)
|
||||
|
@ -201,6 +210,11 @@ func serverCommandAction(cliCtx *cli.Context) error {
|
|||
root.GET("/object/:object", h.getObject)
|
||||
root.GET("/tags/:tag", h.getTaggedObjects)
|
||||
|
||||
root.GET("/avatar/svg/:name", h.avatarSVG)
|
||||
if svgerConfig.Enabled {
|
||||
root.GET("/avatar/png/:name", h.avatarPNG)
|
||||
}
|
||||
|
||||
authenticated := r.Group("/")
|
||||
{
|
||||
configSessionMiddleware(secret, domain, authenticated)
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/ngerakines/tavern/avatar"
|
||||
"github.com/ngerakines/tavern/errors"
|
||||
)
|
||||
|
||||
func (h handler) avatarSVG(c *gin.Context) {
|
||||
svg, err := h.avatar(c)
|
||||
if err != nil {
|
||||
h.hardFail(c, err)
|
||||
return
|
||||
}
|
||||
svgReader := bytes.NewReader(svg)
|
||||
|
||||
extraHeaders := map[string]string{
|
||||
"Cache-Control": "max-age=7200",
|
||||
}
|
||||
c.DataFromReader(http.StatusOK, svgReader.Size(), "image/svg+xml", svgReader, extraHeaders)
|
||||
}
|
||||
|
||||
func (h handler) avatarPNG(c *gin.Context) {
|
||||
svg, err := h.avatar(c)
|
||||
if err != nil {
|
||||
h.hardFail(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
readerCloser, length, err := h.svgConverter.Convert(c.Request.Context(), svg)
|
||||
if err != nil {
|
||||
h.hardFail(c, err)
|
||||
return
|
||||
}
|
||||
defer readerCloser.Close()
|
||||
|
||||
extraHeaders := map[string]string{
|
||||
"Cache-Control": "max-age=7200",
|
||||
}
|
||||
c.DataFromReader(http.StatusOK, length, "image/png", readerCloser, extraHeaders)
|
||||
}
|
||||
|
||||
func (h handler) avatar(c *gin.Context) ([]byte, error) {
|
||||
name := c.Param("name")
|
||||
|
||||
size := intParam(c, "size", 120)
|
||||
|
||||
exists, err := h.storage.RowCount(c.Request.Context(), `SELECT COUNT(*) FROM users WHERE name = $1`, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exists == 0 {
|
||||
return nil, errors.NewNotFoundError(nil)
|
||||
}
|
||||
|
||||
id := fmt.Sprintf("@%s@%s", name, h.domain)
|
||||
svg := avatar.AvatarSVG(id, size)
|
||||
return []byte(svg), nil
|
||||
}
|
|
@ -22,9 +22,10 @@ type handler struct {
|
|||
domain string
|
||||
sentryConfig config.SentryConfig
|
||||
webFingerQueue storage.StringQueue
|
||||
crawlQueue storage.StringQueue
|
||||
crawlQueue storage.StringQueue
|
||||
adminUser string
|
||||
url func(parts ...interface{}) string
|
||||
svgConverter SVGConverter
|
||||
}
|
||||
|
||||
func (h handler) hardFail(ctx *gin.Context, err error, fields ...zap.Field) {
|
||||
|
|
|
@ -14,9 +14,9 @@ import (
|
|||
"github.com/yukimochi/httpsig"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/errors"
|
||||
"github.com/ngerakines/tavern/fed"
|
||||
"github.com/ngerakines/tavern/job"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
)
|
||||
|
||||
|
@ -181,7 +181,7 @@ func (h handler) actorInboxFollow(c *gin.Context, user *storage.User, payload st
|
|||
|
||||
if user.AcceptFollowers {
|
||||
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, job.DefaultHTTPClient(), target)
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), target)
|
||||
if err != nil {
|
||||
h.internalServerErrorJSON(c, err)
|
||||
return
|
||||
|
@ -199,7 +199,7 @@ func (h handler) actorInboxFollow(c *gin.Context, user *storage.User, payload st
|
|||
responsePayload := response.Bytes()
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: job.DefaultHTTPClient(),
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, storage.LocalActor{User: user, ActorID: userActorID}, followerActor, responsePayload)
|
||||
|
@ -407,7 +407,7 @@ func (h handler) actorInboxAnnounce(c *gin.Context, user *storage.User, payload
|
|||
}
|
||||
|
||||
ac := fed.ActivityClient{
|
||||
HTTPClient: job.DefaultHTTPClient(),
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
Logger: h.logger,
|
||||
}
|
||||
localActorID := storage.NewActorID(user.Name, h.domain)
|
||||
|
|
|
@ -11,9 +11,9 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/errors"
|
||||
"github.com/ngerakines/tavern/fed"
|
||||
"github.com/ngerakines/tavern/job"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
)
|
||||
|
||||
|
@ -103,7 +103,7 @@ func (h handler) createNote(c *gin.Context) {
|
|||
mentionedActorNames := storage.FindMentionedActors(content)
|
||||
mentionedActors := make(map[string]storage.Actor)
|
||||
for _, mentionedActor := range mentionedActorNames {
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, job.DefaultHTTPClient(), mentionedActor)
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), mentionedActor)
|
||||
if err == nil {
|
||||
mentionedActors[mentionedActor] = foundActor
|
||||
to = append(to, foundActor.GetID())
|
||||
|
@ -204,7 +204,7 @@ func (h handler) createNote(c *gin.Context) {
|
|||
if ok {
|
||||
continue
|
||||
}
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, job.DefaultHTTPClient(), follower)
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), follower)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ func (h handler) createNote(c *gin.Context) {
|
|||
}
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: job.DefaultHTTPClient(),
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
Logger: h.logger,
|
||||
}
|
||||
localActor := storage.LocalActor{User: user, ActorID: storage.NewActorID(user.Name, h.domain)}
|
||||
|
@ -290,7 +290,7 @@ func (h handler) announceNote(c *gin.Context) {
|
|||
}
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: job.DefaultHTTPClient(),
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.Broadcast(ctx, h.storage, storage.LocalActor{User: user, ActorID: storage.NewActorID(user.Name, h.domain)}, announcePayload)
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/errors"
|
||||
"github.com/ngerakines/tavern/fed"
|
||||
"github.com/ngerakines/tavern/job"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
)
|
||||
|
||||
|
@ -105,7 +105,7 @@ func (h handler) networkFollow(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
actor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, job.DefaultHTTPClient(), c.PostForm("actor"))
|
||||
actor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), c.PostForm("actor"))
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, "/dashboard/network", err)
|
||||
return
|
||||
|
@ -133,7 +133,7 @@ func (h handler) networkFollow(c *gin.Context) {
|
|||
fmt.Println(string(payload))
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: job.DefaultHTTPClient(),
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, storage.LocalActor{User: user, ActorID: storage.NewActorID(user.Name, h.domain),}, actor, payload)
|
||||
|
@ -196,7 +196,7 @@ func (h handler) networkUnfollow(c *gin.Context) {
|
|||
payload := undoFollow.Bytes()
|
||||
fmt.Println(string(payload))
|
||||
|
||||
actor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, job.DefaultHTTPClient(), to)
|
||||
actor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), to)
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, "/dashboard/network", err)
|
||||
return
|
||||
|
@ -209,7 +209,7 @@ func (h handler) networkUnfollow(c *gin.Context) {
|
|||
}
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: job.DefaultHTTPClient(),
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, storage.LocalActor{User: user, ActorID: storage.NewActorID(user.Name, h.domain),}, actor, payload)
|
||||
|
@ -243,7 +243,7 @@ func (h handler) networkAccept(c *gin.Context) {
|
|||
|
||||
targetActorID := c.PostForm("actor")
|
||||
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, job.DefaultHTTPClient(), targetActorID)
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), targetActorID)
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, "/dashboard/network", err)
|
||||
return
|
||||
|
@ -266,7 +266,7 @@ func (h handler) networkAccept(c *gin.Context) {
|
|||
responsePayload := response.Bytes()
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: job.DefaultHTTPClient(),
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, storage.LocalActor{User: user, ActorID: storage.NewActorID(user.Name, h.domain),}, followerActor, responsePayload)
|
||||
|
@ -284,7 +284,6 @@ func (h handler) networkAccept(c *gin.Context) {
|
|||
c.Redirect(http.StatusFound, "/dashboard/network")
|
||||
}
|
||||
|
||||
|
||||
func (h handler) networkReject(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
ctx := c.Request.Context()
|
||||
|
@ -307,7 +306,7 @@ func (h handler) networkReject(c *gin.Context) {
|
|||
|
||||
targetActorID := c.PostForm("actor")
|
||||
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, job.DefaultHTTPClient(), targetActorID)
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), targetActorID)
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, "/dashboard/network", err)
|
||||
return
|
||||
|
@ -330,7 +329,7 @@ func (h handler) networkReject(c *gin.Context) {
|
|||
responsePayload := response.Bytes()
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: job.DefaultHTTPClient(),
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, storage.LocalActor{User: user, ActorID: storage.NewActorID(user.Name, h.domain),}, followerActor, responsePayload)
|
||||
|
|
|
@ -98,6 +98,13 @@ func (h handler) webFinger(c *gin.Context) {
|
|||
self["href"] = fmt.Sprintf("https://%s/users/%s", domain, user.Name)
|
||||
response["links"] = []storage.Payload{self}
|
||||
|
||||
icon := storage.EmptyPayload()
|
||||
icon["type"] = "Image"
|
||||
icon["mediaType"] = "image/png"
|
||||
icon["url"] = fmt.Sprintf("https://%s/avatar/png/%s", h.domain, user.Name)
|
||||
|
||||
self["icon"] = icon
|
||||
|
||||
h.writeJRD(c, http.StatusOK, response)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/g"
|
||||
)
|
||||
|
||||
type SVGConverter interface {
|
||||
Convert(ctx context.Context, svg []byte) (io.ReadCloser, int64, error)
|
||||
}
|
||||
|
||||
type SVGerClient struct {
|
||||
HTTPClient common.HTTPClient
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
func DefaultSVGerClient(endpoint string) SVGConverter {
|
||||
return SVGerClient{
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
}
|
||||
|
||||
func (c SVGerClient) Convert(ctx context.Context, svg []byte) (io.ReadCloser, int64, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", c.Endpoint, bytes.NewBuffer(svg))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "image/svg+xml")
|
||||
req.Header.Set("User-Agent", g.UserAgent())
|
||||
|
||||
response, err := c.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, 0, fmt.Errorf("unexpected response: %d", response.StatusCode)
|
||||
}
|
||||
return response.Body, response.ContentLength, nil
|
||||
}
|
Loading…
Reference in New Issue