Implement JSONLoad, To, and On functions for ForgeFed types
This commit is contained in:
parent
6a6c6b3481
commit
27cda2fcd4
10 changed files with 326 additions and 82 deletions
2
go.mod
2
go.mod
|
@ -299,7 +299,7 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142
|
||||||
|
|
||||||
replace github.com/satori/go.uuid v1.2.0 => github.com/gofrs/uuid v4.2.0+incompatible
|
replace github.com/satori/go.uuid v1.2.0 => github.com/gofrs/uuid v4.2.0+incompatible
|
||||||
|
|
||||||
replace github.com/go-ap/activitypub => gitea.com/Ta180m/activitypub v0.0.0-20220711172827-b05423b54985
|
replace github.com/go-ap/activitypub => gitea.com/Ta180m/activitypub v0.0.0-20220821033718-79a43a998240
|
||||||
|
|
||||||
exclude github.com/gofrs/uuid v3.2.0+incompatible
|
exclude github.com/gofrs/uuid v3.2.0+incompatible
|
||||||
|
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -73,8 +73,8 @@ contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcig
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
|
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
|
||||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||||
gitea.com/Ta180m/activitypub v0.0.0-20220711172827-b05423b54985 h1:mFjFQxAsUdcvtM3klWtTbkhGnsRVF+DPhZPofsKmPlk=
|
gitea.com/Ta180m/activitypub v0.0.0-20220821033718-79a43a998240 h1:ZW+5jY1ibiRPGoBlUcwBA9eHdFVGD70qWrKXw877Yd4=
|
||||||
gitea.com/Ta180m/activitypub v0.0.0-20220711172827-b05423b54985/go.mod h1:KDY/LAOthmTlRA4ft9TKrvPKVe+AZaSaU+3HS/UITvU=
|
gitea.com/Ta180m/activitypub v0.0.0-20220821033718-79a43a998240/go.mod h1:Md4CYDr9vFkojPjSqzG04PN03hgnd+X3jf4i8Nbb7OE=
|
||||||
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb h1:Yy0Bxzc8R2wxiwXoG/rECGplJUSpXqCsog9PuJFgiHs=
|
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb h1:Yy0Bxzc8R2wxiwXoG/rECGplJUSpXqCsog9PuJFgiHs=
|
||||||
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc=
|
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc=
|
||||||
gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0=
|
gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0=
|
||||||
|
|
|
@ -27,6 +27,7 @@ func AuthorizeInteraction(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ap.ItemTyperFunc = forgefed.GetItemByType
|
ap.ItemTyperFunc = forgefed.GetItemByType
|
||||||
|
ap.JSONItemUnmarshal = forgefed.JSONUnmarshalerFn
|
||||||
object, err := ap.UnmarshalJSON(resp)
|
object, err := ap.UnmarshalJSON(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("UnmarshalJSON", err)
|
ctx.ServerError("UnmarshalJSON", err)
|
||||||
|
@ -51,11 +52,19 @@ func AuthorizeInteraction(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
ctx.Redirect(name)
|
ctx.Redirect(name)
|
||||||
case forgefed.RepositoryType:
|
case forgefed.RepositoryType:
|
||||||
err = FederatedRepoNew(ctx, object.(forgefed.Repository))
|
err = forgefed.OnRepository(object, func(r *forgefed.Repository) error {
|
||||||
|
return FederatedRepoNew(ctx, r)
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("FederatedRepoNew", err)
|
ctx.ServerError("FederatedRepoNew", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
username, reponame, err := repositoryIRIToName(object.GetLink())
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("repositoryIRIToName", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Redirect(username+"/"+reponame)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusOK)
|
ctx.Status(http.StatusOK)
|
||||||
|
|
|
@ -8,12 +8,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
"code.gitea.io/gitea/modules/forgefed"
|
"code.gitea.io/gitea/modules/forgefed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create a new federated repo from a Repository object
|
// Create a new federated repo from a Repository object
|
||||||
func FederatedRepoNew(ctx context.Context, repository forgefed.Repository) error {
|
func FederatedRepoNew(ctx context.Context, repository *forgefed.Repository) error {
|
||||||
ownerIRI, err := repositoryIRIToOwnerIRI(repository.GetLink())
|
ownerIRI, err := repositoryIRIToOwnerIRI(repository.GetLink())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -23,9 +23,14 @@ func FederatedRepoNew(ctx context.Context, repository forgefed.Repository) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo := repo_model.Repository{
|
// TODO: Check if repo already exists
|
||||||
|
repo, err := repo_service.CreateRepository(user, user, models.CreateRepoOptions{
|
||||||
Name: repository.Name.String(),
|
Name: repository.Name.String(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if repository.ForkedFrom != nil {
|
if repository.ForkedFrom != nil {
|
||||||
repo.IsFork = true
|
repo.IsFork = true
|
||||||
forkedFrom, err := repositoryIRIToRepository(ctx, repository.ForkedFrom.GetLink())
|
forkedFrom, err := repositoryIRIToRepository(ctx, repository.ForkedFrom.GetLink())
|
||||||
|
@ -34,7 +39,5 @@ func FederatedRepoNew(ctx context.Context, repository forgefed.Repository) error
|
||||||
}
|
}
|
||||||
repo.ForkID = forkedFrom.ID
|
repo.ForkID = forkedFrom.ID
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
// TODO: Check if repo already exists
|
|
||||||
return models.CreateRepository(ctx, user, user, &repo, false)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
package forgefed
|
package forgefed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
ap "github.com/go-ap/activitypub"
|
||||||
"github.com/valyala/fastjson"
|
"github.com/valyala/fastjson"
|
||||||
)
|
)
|
||||||
|
@ -26,30 +29,68 @@ func BranchNew() *Branch {
|
||||||
return &o
|
return &o
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br Branch) MarshalJSON() ([]byte, error) {
|
func (b Branch) MarshalJSON() ([]byte, error) {
|
||||||
b, err := br.Object.MarshalJSON()
|
bin, err := b.Object.MarshalJSON()
|
||||||
if len(b) == 0 || err != nil {
|
if len(bin) == 0 || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b = b[:len(b)-1]
|
bin = bin[:len(bin)-1]
|
||||||
if br.Ref != nil {
|
if b.Ref != nil {
|
||||||
ap.WriteItemJSONProp(&b, "ref", br.Ref)
|
ap.JSONWriteItemJSONProp(&bin, "ref", b.Ref)
|
||||||
}
|
}
|
||||||
ap.Write(&b, '}')
|
ap.JSONWrite(&bin, '}')
|
||||||
return b, nil
|
return bin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *Branch) UnmarshalJSON(data []byte) error {
|
func JSONLoadBranch(val *fastjson.Value, b *Branch) error {
|
||||||
|
ap.OnObject(&b.Object, func(o *ap.Object) error {
|
||||||
|
return ap.JSONLoadObject(val, o)
|
||||||
|
})
|
||||||
|
b.Ref = ap.JSONGetItem(val, "ref")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Branch) UnmarshalJSON(data []byte) error {
|
||||||
p := fastjson.Parser{}
|
p := fastjson.Parser{}
|
||||||
val, err := p.ParseBytes(data)
|
val, err := p.ParseBytes(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return JSONLoadBranch(val, b)
|
||||||
br.Ref = ap.JSONGetItem(val, "ref")
|
}
|
||||||
|
|
||||||
return ap.OnObject(&br.Object, func(a *ap.Object) error {
|
// ToBranch tries to convert the it Item to a Branch object.
|
||||||
return ap.LoadObject(val, a)
|
func ToBranch(it ap.Item) (*Branch, error) {
|
||||||
})
|
switch i := it.(type) {
|
||||||
|
case *Branch:
|
||||||
|
return i, nil
|
||||||
|
case Branch:
|
||||||
|
return &i, nil
|
||||||
|
case *ap.Object:
|
||||||
|
return (*Branch)(unsafe.Pointer(i)), nil
|
||||||
|
case ap.Object:
|
||||||
|
return (*Branch)(unsafe.Pointer(&i)), nil
|
||||||
|
default:
|
||||||
|
// NOTE(marius): this is an ugly way of dealing with the interface conversion error: types from different scopes
|
||||||
|
typ := reflect.TypeOf(new(Branch))
|
||||||
|
if i, ok := reflect.ValueOf(it).Convert(typ).Interface().(*Branch); ok {
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, ap.ErrorInvalidType[ap.Object](it)
|
||||||
|
}
|
||||||
|
|
||||||
|
type withBranchFn func(*Branch) error
|
||||||
|
|
||||||
|
// OnBranch calls function fn on it Item if it can be asserted to type *Branch
|
||||||
|
func OnBranch(it ap.Item, fn withBranchFn) error {
|
||||||
|
if it == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ob, err := ToBranch(it)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fn(ob)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
package forgefed
|
package forgefed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
ap "github.com/go-ap/activitypub"
|
||||||
"github.com/valyala/fastjson"
|
"github.com/valyala/fastjson"
|
||||||
|
@ -38,26 +40,64 @@ func (c Commit) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
b = b[:len(b)-1]
|
b = b[:len(b)-1]
|
||||||
if !c.Created.IsZero() {
|
if !c.Created.IsZero() {
|
||||||
ap.WriteTimeJSONProp(&b, "created", c.Created)
|
ap.JSONWriteTimeJSONProp(&b, "created", c.Created)
|
||||||
}
|
}
|
||||||
if !c.Committed.IsZero() {
|
if !c.Committed.IsZero() {
|
||||||
ap.WriteTimeJSONProp(&b, "committed", c.Committed)
|
ap.JSONWriteTimeJSONProp(&b, "committed", c.Committed)
|
||||||
}
|
}
|
||||||
ap.Write(&b, '}')
|
ap.JSONWrite(&b, '}')
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JSONLoadCommit(val *fastjson.Value, c *Commit) error {
|
||||||
|
ap.OnObject(&c.Object, func(o *ap.Object) error {
|
||||||
|
return ap.JSONLoadObject(val, o)
|
||||||
|
})
|
||||||
|
c.Created = ap.JSONGetTime(val, "created")
|
||||||
|
c.Committed = ap.JSONGetTime(val, "committed")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Commit) UnmarshalJSON(data []byte) error {
|
func (c *Commit) UnmarshalJSON(data []byte) error {
|
||||||
p := fastjson.Parser{}
|
p := fastjson.Parser{}
|
||||||
val, err := p.ParseBytes(data)
|
val, err := p.ParseBytes(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return JSONLoadCommit(val, c)
|
||||||
c.Created = ap.JSONGetTime(val, "created")
|
}
|
||||||
c.Committed = ap.JSONGetTime(val, "committed")
|
|
||||||
|
// ToCommit tries to convert the it Item to a Commit object.
|
||||||
return ap.OnObject(&c.Object, func(a *ap.Object) error {
|
func ToCommit(it ap.Item) (*Commit, error) {
|
||||||
return ap.LoadObject(val, a)
|
switch i := it.(type) {
|
||||||
})
|
case *Commit:
|
||||||
|
return i, nil
|
||||||
|
case Commit:
|
||||||
|
return &i, nil
|
||||||
|
case *ap.Object:
|
||||||
|
return (*Commit)(unsafe.Pointer(i)), nil
|
||||||
|
case ap.Object:
|
||||||
|
return (*Commit)(unsafe.Pointer(&i)), nil
|
||||||
|
default:
|
||||||
|
// NOTE(marius): this is an ugly way of dealing with the interface conversion error: types from different scopes
|
||||||
|
typ := reflect.TypeOf(new(Commit))
|
||||||
|
if i, ok := reflect.ValueOf(it).Convert(typ).Interface().(*Commit); ok {
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, ap.ErrorInvalidType[ap.Object](it)
|
||||||
|
}
|
||||||
|
|
||||||
|
type withCommitFn func(*Commit) error
|
||||||
|
|
||||||
|
// OnCommit calls function fn on it Item if it can be asserted to type *Commit
|
||||||
|
func OnCommit(it ap.Item, fn withCommitFn) error {
|
||||||
|
if it == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ob, err := ToCommit(it)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fn(ob)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ package forgefed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
ap "github.com/go-ap/activitypub"
|
ap "github.com/go-ap/activitypub"
|
||||||
|
"github.com/valyala/fastjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ForgeFedNamespaceURI = "https://forgefed.org/ns"
|
const ForgeFedNamespaceURI = "https://forgefed.org/ns"
|
||||||
|
@ -27,3 +28,31 @@ func GetItemByType(typ ap.ActivityVocabularyType) (ap.Item, error) {
|
||||||
}
|
}
|
||||||
return ap.GetItemByType(typ)
|
return ap.GetItemByType(typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSONUnmarshalerFn is the type of the function that will load the data from a fastjson.Value into an Item
|
||||||
|
// that the go-ap/activitypub package doesn't know about.
|
||||||
|
func JSONUnmarshalerFn(typ ap.ActivityVocabularyType, val *fastjson.Value, i ap.Item) error {
|
||||||
|
switch typ {
|
||||||
|
case CommitType:
|
||||||
|
return OnCommit(i, func(c *Commit) error {
|
||||||
|
return JSONLoadCommit(val, c)
|
||||||
|
})
|
||||||
|
case BranchType:
|
||||||
|
return OnBranch(i, func(b *Branch) error {
|
||||||
|
return JSONLoadBranch(val, b)
|
||||||
|
})
|
||||||
|
case RepositoryType:
|
||||||
|
return OnRepository(i, func(r *Repository) error {
|
||||||
|
return JSONLoadRepository(val, r)
|
||||||
|
})
|
||||||
|
case PushType:
|
||||||
|
return OnPush(i, func(p *Push) error {
|
||||||
|
return JSONLoadPush(val, p)
|
||||||
|
})
|
||||||
|
case TicketType:
|
||||||
|
return OnTicket(i, func(t *Ticket) error {
|
||||||
|
return JSONLoadTicket(val, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
package forgefed
|
package forgefed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
ap "github.com/go-ap/activitypub"
|
||||||
"github.com/valyala/fastjson"
|
"github.com/valyala/fastjson"
|
||||||
)
|
)
|
||||||
|
@ -38,30 +41,68 @@ func (p Push) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
b = b[:len(b)-1]
|
b = b[:len(b)-1]
|
||||||
if p.Target != nil {
|
if p.Target != nil {
|
||||||
ap.WriteItemJSONProp(&b, "target", p.Target)
|
ap.JSONWriteItemJSONProp(&b, "target", p.Target)
|
||||||
}
|
}
|
||||||
if p.HashBefore != nil {
|
if p.HashBefore != nil {
|
||||||
ap.WriteItemJSONProp(&b, "hashBefore", p.HashBefore)
|
ap.JSONWriteItemJSONProp(&b, "hashBefore", p.HashBefore)
|
||||||
}
|
}
|
||||||
if p.HashAfter != nil {
|
if p.HashAfter != nil {
|
||||||
ap.WriteItemJSONProp(&b, "hashAfter", p.HashAfter)
|
ap.JSONWriteItemJSONProp(&b, "hashAfter", p.HashAfter)
|
||||||
}
|
}
|
||||||
ap.Write(&b, '}')
|
ap.JSONWrite(&b, '}')
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Push) UnmarshalJSON(data []byte) error {
|
func JSONLoadPush(val *fastjson.Value, p *Push) error {
|
||||||
ps := fastjson.Parser{}
|
ap.OnObject(&p.Object, func(o *ap.Object) error {
|
||||||
val, err := ps.ParseBytes(data)
|
return ap.JSONLoadObject(val, o)
|
||||||
if err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Target = ap.JSONGetItem(val, "target")
|
p.Target = ap.JSONGetItem(val, "target")
|
||||||
p.HashBefore = ap.JSONGetItem(val, "hashBefore")
|
p.HashBefore = ap.JSONGetItem(val, "hashBefore")
|
||||||
p.HashAfter = ap.JSONGetItem(val, "hashAfter")
|
p.HashAfter = ap.JSONGetItem(val, "hashAfter")
|
||||||
|
return nil
|
||||||
return ap.OnObject(&p.Object, func(a *ap.Object) error {
|
}
|
||||||
return ap.LoadObject(val, a)
|
|
||||||
})
|
func (p *Push) UnmarshalJSON(data []byte) error {
|
||||||
|
par := fastjson.Parser{}
|
||||||
|
val, err := par.ParseBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return JSONLoadPush(val, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPush tries to convert the it Item to a Push object.
|
||||||
|
func ToPush(it ap.Item) (*Push, error) {
|
||||||
|
switch i := it.(type) {
|
||||||
|
case *Push:
|
||||||
|
return i, nil
|
||||||
|
case Push:
|
||||||
|
return &i, nil
|
||||||
|
case *ap.Object:
|
||||||
|
return (*Push)(unsafe.Pointer(i)), nil
|
||||||
|
case ap.Object:
|
||||||
|
return (*Push)(unsafe.Pointer(&i)), nil
|
||||||
|
default:
|
||||||
|
// NOTE(marius): this is an ugly way of dealing with the interface conversion error: types from different scopes
|
||||||
|
typ := reflect.TypeOf(new(Push))
|
||||||
|
if i, ok := reflect.ValueOf(it).Convert(typ).Interface().(*Push); ok {
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, ap.ErrorInvalidType[ap.Object](it)
|
||||||
|
}
|
||||||
|
|
||||||
|
type withPushFn func(*Push) error
|
||||||
|
|
||||||
|
// OnPush calls function fn on it Item if it can be asserted to type *Push
|
||||||
|
func OnPush(it ap.Item, fn withPushFn) error {
|
||||||
|
if it == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ob, err := ToPush(it)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fn(ob)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
package forgefed
|
package forgefed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
ap "github.com/go-ap/activitypub"
|
||||||
"github.com/valyala/fastjson"
|
"github.com/valyala/fastjson"
|
||||||
)
|
)
|
||||||
|
@ -39,30 +42,68 @@ func (r Repository) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
b = b[:len(b)-1]
|
b = b[:len(b)-1]
|
||||||
if r.Team != nil {
|
if r.Team != nil {
|
||||||
ap.WriteItemJSONProp(&b, "team", r.Team)
|
ap.JSONWriteItemJSONProp(&b, "team", r.Team)
|
||||||
}
|
}
|
||||||
if r.Forks != nil {
|
if r.Forks != nil {
|
||||||
ap.WriteItemJSONProp(&b, "forks", r.Forks)
|
ap.JSONWriteItemJSONProp(&b, "forks", r.Forks)
|
||||||
}
|
}
|
||||||
if r.ForkedFrom != nil {
|
if r.ForkedFrom != nil {
|
||||||
ap.WriteItemJSONProp(&b, "forkedFrom", r.ForkedFrom)
|
ap.JSONWriteItemJSONProp(&b, "forkedFrom", r.ForkedFrom)
|
||||||
}
|
}
|
||||||
ap.Write(&b, '}')
|
ap.JSONWrite(&b, '}')
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JSONLoadRepository(val *fastjson.Value, r *Repository) error {
|
||||||
|
ap.OnActor(&r.Actor, func(a *ap.Actor) error {
|
||||||
|
return ap.JSONLoadActor(val, a)
|
||||||
|
})
|
||||||
|
r.Team = ap.JSONGetItem(val, "team")
|
||||||
|
r.Forks = ap.JSONGetItem(val, "forks")
|
||||||
|
r.ForkedFrom = ap.JSONGetItem(val, "forkedFrom")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Repository) UnmarshalJSON(data []byte) error {
|
func (r *Repository) UnmarshalJSON(data []byte) error {
|
||||||
p := fastjson.Parser{}
|
p := fastjson.Parser{}
|
||||||
val, err := p.ParseBytes(data)
|
val, err := p.ParseBytes(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return JSONLoadRepository(val, r)
|
||||||
r.Team = ap.JSONGetItem(val, "team")
|
}
|
||||||
r.Forks = ap.JSONGetItem(val, "forks")
|
|
||||||
r.ForkedFrom = ap.JSONGetItem(val, "forkedFrom")
|
// ToRepository tries to convert the it Item to a Repository Actor.
|
||||||
|
func ToRepository(it ap.Item) (*Repository, error) {
|
||||||
return ap.OnActor(&r.Actor, func(a *ap.Actor) error {
|
switch i := it.(type) {
|
||||||
return ap.LoadActor(val, a)
|
case *Repository:
|
||||||
})
|
return i, nil
|
||||||
|
case Repository:
|
||||||
|
return &i, nil
|
||||||
|
case *ap.Actor:
|
||||||
|
return (*Repository)(unsafe.Pointer(i)), nil
|
||||||
|
case ap.Actor:
|
||||||
|
return (*Repository)(unsafe.Pointer(&i)), nil
|
||||||
|
default:
|
||||||
|
// NOTE(marius): this is an ugly way of dealing with the interface conversion error: types from different scopes
|
||||||
|
typ := reflect.TypeOf(new(Repository))
|
||||||
|
if i, ok := reflect.ValueOf(it).Convert(typ).Interface().(*Repository); ok {
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, ap.ErrorInvalidType[ap.Actor](it)
|
||||||
|
}
|
||||||
|
|
||||||
|
type withRepositoryFn func(*Repository) error
|
||||||
|
|
||||||
|
// OnRepository calls function fn on it Item if it can be asserted to type *Repository
|
||||||
|
func OnRepository(it ap.Item, fn withRepositoryFn) error {
|
||||||
|
if it == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ob, err := ToRepository(it)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fn(ob)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
package forgefed
|
package forgefed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
ap "github.com/go-ap/activitypub"
|
||||||
"github.com/valyala/fastjson"
|
"github.com/valyala/fastjson"
|
||||||
|
@ -48,44 +50,82 @@ func (t Ticket) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
b = b[:len(b)-1]
|
b = b[:len(b)-1]
|
||||||
if t.Dependants != nil {
|
if t.Dependants != nil {
|
||||||
ap.WriteItemCollectionJSONProp(&b, "dependants", t.Dependants)
|
ap.JSONWriteItemCollectionJSONProp(&b, "dependants", t.Dependants)
|
||||||
}
|
}
|
||||||
if t.Dependencies != nil {
|
if t.Dependencies != nil {
|
||||||
ap.WriteItemCollectionJSONProp(&b, "dependencies", t.Dependencies)
|
ap.JSONWriteItemCollectionJSONProp(&b, "dependencies", t.Dependencies)
|
||||||
}
|
}
|
||||||
ap.WriteBoolJSONProp(&b, "isResolved", t.IsResolved)
|
ap.JSONWriteBoolJSONProp(&b, "isResolved", t.IsResolved)
|
||||||
if t.ResolvedBy != nil {
|
if t.ResolvedBy != nil {
|
||||||
ap.WriteItemJSONProp(&b, "resolvedBy", t.ResolvedBy)
|
ap.JSONWriteItemJSONProp(&b, "resolvedBy", t.ResolvedBy)
|
||||||
}
|
}
|
||||||
if !t.Resolved.IsZero() {
|
if !t.Resolved.IsZero() {
|
||||||
ap.WriteTimeJSONProp(&b, "resolved", t.Resolved)
|
ap.JSONWriteTimeJSONProp(&b, "resolved", t.Resolved)
|
||||||
}
|
}
|
||||||
if t.Origin != nil {
|
if t.Origin != nil {
|
||||||
ap.WriteItemJSONProp(&b, "origin", t.Origin)
|
ap.JSONWriteItemJSONProp(&b, "origin", t.Origin)
|
||||||
}
|
}
|
||||||
if t.Target != nil {
|
if t.Target != nil {
|
||||||
ap.WriteItemJSONProp(&b, "target", t.Target)
|
ap.JSONWriteItemJSONProp(&b, "target", t.Target)
|
||||||
}
|
}
|
||||||
ap.Write(&b, '}')
|
ap.JSONWrite(&b, '}')
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JSONLoadTicket(val *fastjson.Value, t *Ticket) error {
|
||||||
|
ap.OnObject(&t.Object, func(o *ap.Object) error {
|
||||||
|
return ap.JSONLoadObject(val, o)
|
||||||
|
})
|
||||||
|
t.Dependants = ap.JSONGetItems(val, "dependants")
|
||||||
|
t.Dependencies = ap.JSONGetItems(val, "dependencies")
|
||||||
|
t.IsResolved = ap.JSONGetBoolean(val, "isResolved")
|
||||||
|
t.ResolvedBy = ap.JSONGetItem(val, "resolvedBy")
|
||||||
|
t.Resolved = ap.JSONGetTime(val, "resolved")
|
||||||
|
t.Origin = ap.JSONGetItem(val, "origin")
|
||||||
|
t.Target = ap.JSONGetItem(val, "target")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Ticket) UnmarshalJSON(data []byte) error {
|
func (t *Ticket) UnmarshalJSON(data []byte) error {
|
||||||
p := fastjson.Parser{}
|
p := fastjson.Parser{}
|
||||||
val, err := p.ParseBytes(data)
|
val, err := p.ParseBytes(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return JSONLoadTicket(val, t)
|
||||||
t.Dependants = ap.JSONGetItems(val, "dependants")
|
}
|
||||||
t.Dependencies = ap.JSONGetItems(val, "dependencies")
|
|
||||||
t.IsResolved = ap.JSONGetBoolean(val, "isResolved")
|
// ToTicket tries to convert the it Item to a Ticket object.
|
||||||
t.ResolvedBy = ap.JSONGetItem(val, "resolvedBy")
|
func ToTicket(it ap.Item) (*Ticket, error) {
|
||||||
t.Resolved = ap.JSONGetTime(val, "resolved")
|
switch i := it.(type) {
|
||||||
t.Origin = ap.JSONGetItem(val, "origin")
|
case *Ticket:
|
||||||
t.Target = ap.JSONGetItem(val, "target")
|
return i, nil
|
||||||
|
case Ticket:
|
||||||
return ap.OnObject(&t.Object, func(a *ap.Object) error {
|
return &i, nil
|
||||||
return ap.LoadObject(val, a)
|
case *ap.Object:
|
||||||
})
|
return (*Ticket)(unsafe.Pointer(i)), nil
|
||||||
|
case ap.Object:
|
||||||
|
return (*Ticket)(unsafe.Pointer(&i)), nil
|
||||||
|
default:
|
||||||
|
// NOTE(marius): this is an ugly way of dealing with the interface conversion error: types from different scopes
|
||||||
|
typ := reflect.TypeOf(new(Ticket))
|
||||||
|
if i, ok := reflect.ValueOf(it).Convert(typ).Interface().(*Ticket); ok {
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, ap.ErrorInvalidType[ap.Object](it)
|
||||||
|
}
|
||||||
|
|
||||||
|
type withTicketFn func(*Ticket) error
|
||||||
|
|
||||||
|
// OnTicket calls function fn on it Item if it can be asserted to type *Ticket
|
||||||
|
func OnTicket(it ap.Item, fn withTicketFn) error {
|
||||||
|
if it == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ob, err := ToTicket(it)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fn(ob)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue