Skip to content

Commit

Permalink
feat: format events
Browse files Browse the repository at this point in the history
  • Loading branch information
akurilov committed Jul 25, 2024
1 parent 1244634 commit d7c7ec5
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 20 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ vendor/
# Go workspace file
go.work

**/*.pb.go
**/*.pb.go
*.pem
secret*.yaml
18 changes: 13 additions & 5 deletions api/http/handler/actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,10 @@ func (ah actorHandler) handleDefault(ctx *gin.Context, accept string) {
}

func (ah actorHandler) handleInterest(ctx *gin.Context, accept, id string) {
urlDetails := ah.urlPrefixInterestDetails + id
switch accept {
case "text/html", "application/xhtml+xml", "text/xml", "application/xml":
ctx.Redirect(http.StatusMovedPermanently, ah.urlPrefixInterestDetails+id)
ctx.Redirect(http.StatusMovedPermanently, urlDetails)
default:
ctxAwk := metadata.AppendToOutgoingContext(ctx, model.KeyGroupId, model.GroupIdDefault)
d, err := ah.clientAwk.ReadSubscription(ctxAwk, model.UserIdDefault, id)
Expand All @@ -112,8 +113,15 @@ func (ah actorHandler) handleInterest(ctx *gin.Context, accept, id string) {
}
actor.ID = vocab.ID(fmt.Sprintf("https://%s/actor/%s", ah.cfgApi.Http.Host, id))
actor.Name = vocab.DefaultNaturalLanguageValue(id)
actor.Summary = vocab.DefaultNaturalLanguageValue(fmt.Sprintf("Awakari Interest: %s", d.Description))
actor.URL = vocab.IRI(ah.urlPrefixInterestDetails + id)
actor.Summary = vocab.DefaultNaturalLanguageValue(
fmt.Sprintf(
`<p>Awakari Interest: <b>%s</b></p>
<p><a href="%s">Details link</a></p>`,
d.Description,
urlDetails,
),
)
actor.URL = vocab.IRI(urlDetails)
actor.Inbox = vocab.IRI(fmt.Sprintf("https://%s/inbox/%s", ah.cfgApi.Http.Host, id))
actor.Outbox = vocab.IRI(fmt.Sprintf("https://%s/outbox/%s", ah.cfgApi.Http.Host, id))
actor.Following = vocab.IRI(fmt.Sprintf("https://%s/following/%s", ah.cfgApi.Http.Host, id))
Expand All @@ -127,8 +135,8 @@ func (ah actorHandler) handleInterest(ctx *gin.Context, accept, id string) {
actor.Attachment = vocab.ItemCollection{
vocab.Page{
Name: vocab.DefaultNaturalLanguageValue("homepage"),
ID: vocab.ID(ah.urlPrefixInterestDetails + id),
URL: vocab.IRI(ah.urlPrefixInterestDetails + id),
ID: vocab.ID(urlDetails),
URL: vocab.IRI(urlDetails),
},
}
aFixed, cs := apiHttp.FixContext(actor)
Expand Down
111 changes: 97 additions & 14 deletions service/converter/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package converter

import (
"context"
"encoding/base64"
"errors"
"fmt"
"github.com/awakari/int-activitypub/model"
Expand All @@ -12,8 +13,10 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"
"net/url"
"reflect"
"sort"
"strings"
"time"
"unicode/utf8"
)

type Service interface {
Expand Down Expand Up @@ -53,6 +56,9 @@ const CeKeyUpdated = "updated"

const asPublic = "https://www.w3.org/ns/activitystreams#Public"

const fmtLenMaxAttrVal = 80
const fmtLenMaxBodyTxt = 240

var ErrFail = errors.New("failed to convert")

func NewService(ceType, urlBase string, actorType vocab.ActivityVocabularyType) Service {
Expand Down Expand Up @@ -505,21 +511,94 @@ func (svc service) ConvertEventToActivity(ctx context.Context, evt *pb.CloudEven
follower.ID,
})
}
txt := evt.GetTextData()
var ceObj string
var objType vocab.ActivityVocabularyType
attrObj, objPresent := evt.Attributes[CeKeyObject]
if objPresent {
objType = vocab.ActivityVocabularyType(attrObj.GetCeString())
if objType == "" {
objType = vocab.ActivityVocabularyType(attrObj.GetCeUri())
ceObj = attrObj.GetCeString()
if ceObj == "" {
ceObj = attrObj.GetCeUri()
}
}
if !vocab.ObjectTypes.Contains(objType) {
switch vocab.ObjectTypes.Contains(vocab.ActivityVocabularyType(ceObj)) {
case true:
objType = vocab.ActivityVocabularyType(ceObj)
default:
objType = vocab.NoteType
}
obj := vocab.ObjectNew(objType)
a.Object = obj
obj.ID = vocab.ID(svc.urlBase + "/" + evt.Id)
obj.URL = obj.ID
switch {
case strings.HasPrefix("http://", ceObj):
fallthrough
case strings.HasPrefix("https://", ceObj):
obj.URL = vocab.IRI(ceObj)
default:
obj.URL = obj.ID
}
attrObjUrl, attrObjUrlPresent := evt.Attributes[CeKeyObjectUrl]
if attrObjUrlPresent {
objUrl := attrObjUrl.GetCeString()
if objUrl == "" {
objUrl = attrObjUrl.GetCeUri()
}
obj.URL = vocab.IRI(objUrl)
}
txt += fmt.Sprintf(
"<p><a href=\"%s\">%s</a></p><p><u>id</u>: %s\n<u>source</u>: %s\n<u>type</u>: %s\n",
obj.URL.GetLink().String(),
obj.URL.GetLink().String(),
evt.Id,
evt.Source,
evt.Type,
)
var attrNames []string
for attrName, _ := range evt.Attributes {
attrNames = append(attrNames, attrName)
}
sort.Strings(attrNames)
for _, attrName := range attrNames {
switch attrName {
case "awakarimatchfound": // internal
case "awakariuserid": // do not expose
case "awkinternal": // internal
default:
attrVal := evt.Attributes[attrName]
switch vt := attrVal.Attr.(type) {
case *pb.CloudEventAttributeValue_CeBoolean:
switch vt.CeBoolean {
case true:
txt += fmt.Sprintf("<u>%s</u>: true\n", attrName)
default:
txt += fmt.Sprintf("<u>%s</u>: false\n", attrName)
}
case *pb.CloudEventAttributeValue_CeInteger:
txt += fmt.Sprintf("<u>%s</u>: %d\n", attrName, vt.CeInteger)
case *pb.CloudEventAttributeValue_CeString:
if vt.CeString != evt.Source { // "object"/"objecturl" might the same value as the source
v := truncateStringUtf8(vt.CeString, fmtLenMaxAttrVal)
txt += fmt.Sprintf("<u>%s</u>: %s\n", attrName, v)
}
case *pb.CloudEventAttributeValue_CeUri:
v := truncateStringUtf8(vt.CeUri, fmtLenMaxAttrVal)
txt += fmt.Sprintf("<u>%s</u>: %s\n", attrName, v)
case *pb.CloudEventAttributeValue_CeUriRef:
v := truncateStringUtf8(vt.CeUriRef, fmtLenMaxAttrVal)
txt += fmt.Sprintf("<u>%s</u>: %s\n", attrName, v)
case *pb.CloudEventAttributeValue_CeTimestamp:
v := vt.CeTimestamp
txt += fmt.Sprintf("<u>%s</u>: %s\n", attrName, v.AsTime().Format(time.RFC3339))
case *pb.CloudEventAttributeValue_CeBytes:
v := base64.StdEncoding.EncodeToString(vt.CeBytes)
v = truncateStringUtf8(v, fmtLenMaxAttrVal)
txt += fmt.Sprintf("<u>%s</u>: %s\n", attrName, v)
}
}
}
txt += "</p>"
obj.Content = vocab.DefaultNaturalLanguageValue(txt)
attrTs, tsPresent := evt.Attributes[CeKeyTime]
if tsPresent {
obj.Published = attrTs.GetCeTimestamp().AsTime()
Expand All @@ -528,20 +607,11 @@ func (svc service) ConvertEventToActivity(ctx context.Context, evt *pb.CloudEven
if tsUpdPresent {
obj.Updated = attrTsUpd.GetCeTimestamp().AsTime()
}
obj.Content = vocab.DefaultNaturalLanguageValue(evt.GetTextData())
obj.To = a.To
obj.CC = a.CC
obj.AttributedTo = vocab.ItemCollection{
a.Actor,
}
attrObjUrl, attrObjUrlPresent := evt.Attributes[CeKeyObjectUrl]
if attrObjUrlPresent {
objUrl := attrObjUrl.GetCeString()
if objUrl == "" {
objUrl = attrObjUrl.GetCeUri()
}
obj.URL = vocab.LinkNew(vocab.ID(objUrl), vocab.LinkType)
}
attrAttType, attrAttTypePresent := evt.Attributes[CeKeyAttachmentType]
attrAttUrl, attrAttUrlPresent := evt.Attributes[CeKeyAttachmentUrl]
if attrAttTypePresent && attrAttUrlPresent {
Expand Down Expand Up @@ -604,3 +674,16 @@ func (svc service) ConvertEventToActivity(ctx context.Context, evt *pb.CloudEven
}
return
}

func truncateStringUtf8(s string, lenMax int) string {
if len(s) <= lenMax {
return s
}
// Ensure we don't split a UTF-8 character in the middle.
for i := lenMax - 3; i > 0; i-- {
if utf8.RuneStart(s[i]) {
return s[:i] + "..."
}
}
return ""
}

0 comments on commit d7c7ec5

Please sign in to comment.