Federated issue creation

This commit is contained in:
Anthony Wang 2022-11-27 19:09:10 +00:00
parent 77896f1a50
commit 3e690fbae2
Signed by: a
GPG key ID: 42A5B952E6DD8D38
6 changed files with 113 additions and 81 deletions

View file

@ -41,6 +41,7 @@ func Repo(ctx *context.APIContext) {
iri := ctx.Repo.Repository.GetIRI()
repo := forgefed.RepositoryNew(ap.IRI(iri))
repo.Type = forgefed.RepositoryType
repo.Name = ap.NaturalLanguageValuesNew()
err := repo.Name.Set("en", ap.Content(ctx.Repo.Repository.Name))
@ -123,24 +124,27 @@ func RepoInbox(ctx *context.APIContext) {
// Process activity
switch activity.Type {
case ap.CreateType:
err = ap.OnObject(activity.Object, func(o *ap.Object) error {
switch o.Type {
case forgefed.RepositoryType:
// Fork created by remote instance
return forgefed.OnRepository(o, func(r *forgefed.Repository) error {
return createRepository(ctx, r)
})
case forgefed.TicketType:
// New issue or pull request
return forgefed.OnTicket(o, func(t *forgefed.Ticket) error {
return createTicket(ctx, t)
})
case ap.NoteType:
// New comment
return createComment(ctx, o)
}
return nil
})
switch activity.Object.GetType() {
case forgefed.RepositoryType:
// Fork created by remote instance
err = forgefed.OnRepository(activity.Object, func(r *forgefed.Repository) error {
return createRepository(ctx, r)
})
case forgefed.TicketType:
// New issue or pull request
err = forgefed.OnTicket(activity.Object, func(t *forgefed.Ticket) error {
return createTicket(ctx, t)
})
case ap.NoteType:
// New comment
err = ap.On(activity.Object, func(n *ap.Note) error {
return createComment(ctx, n)
})
default:
log.Info("Incoming unsupported ActivityStreams object type: %s", activity.Object.GetType())
ctx.PlainText(http.StatusNotImplemented, "ActivityStreams object type not supported")
return
}
case ap.LikeType:
err = star(ctx, activity)
default:
@ -149,7 +153,7 @@ func RepoInbox(ctx *context.APIContext) {
return
}
if err != nil {
ctx.ServerError("Error when processing: %s", err)
ctx.ServerError("Error when processing", err)
}
ctx.Status(http.StatusNoContent)

View file

@ -8,12 +8,8 @@ import (
"strconv"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/forgefed"
"code.gitea.io/gitea/modules/setting"
ap "github.com/go-ap/activitypub"
"code.gitea.io/gitea/services/activitypub"
)
// Ticket function returns the Ticket object for an issue or PR
@ -43,63 +39,20 @@ func Ticket(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/ActivityPub"
repo, err := repo_model.GetRepositoryByOwnerAndNameCtx(ctx, ctx.ContextUser.Name, ctx.Repo.Repository.Name)
if err != nil {
ctx.ServerError("GetRepositoryByOwnerAndNameCtx", err)
return
}
index, err := strconv.ParseInt(ctx.Params("id"), 10, 64)
if err != nil {
ctx.ServerError("ParseInt", err)
return
}
issue, err := issues_model.GetIssueByIndex(repo.ID, index)
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, index)
if err != nil {
ctx.ServerError("GetIssueByIndex", err)
return
}
iri := issue.GetIRI()
// TODO: move this to services/activitypub/objects.go
ticket := forgefed.TicketNew()
ticket.Type = forgefed.TicketType
ticket.ID = ap.IRI(iri)
// Setting a NaturalLanguageValue to a number causes go-ap's JSON parsing to do weird things
// Workaround: set it to #1 instead of 1
ticket.Name = ap.NaturalLanguageValuesNew()
err = ticket.Name.Set("en", ap.Content("#"+ctx.Params("id")))
ticket, err := activitypub.Ticket(issue)
if err != nil {
ctx.ServerError("Set Name", err)
ctx.ServerError("Ticket", err)
return
}
ticket.Context = ap.IRI(setting.AppURL + "api/v1/activitypub/repo/" + ctx.ContextUser.Name + "/" + ctx.Repo.Repository.Name)
err = issue.LoadPoster()
if err != nil {
ctx.ServerError("LoadPoster", err)
return
}
ticket.AttributedTo = ap.IRI(setting.AppURL + "api/v1/activitypub/user/" + issue.Poster.Name)
ticket.Summary = ap.NaturalLanguageValuesNew()
err = ticket.Summary.Set("en", ap.Content(issue.Title))
if err != nil {
ctx.ServerError("Set Summary", err)
return
}
ticket.Content = ap.NaturalLanguageValuesNew()
err = ticket.Content.Set("en", ap.Content(issue.Content))
if err != nil {
ctx.ServerError("Set Content", err)
return
}
if issue.IsClosed {
ticket.IsResolved = true
}
response(ctx, ticket)
}

View file

@ -0,0 +1,17 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package activitypub
import (
ap "github.com/go-ap/activitypub"
)
func Create(to string, object ap.ObjectOrLink) *ap.Create {
return &ap.Create{
Type: ap.CreateType,
Object: object,
To: ap.ItemCollection{ap.Item(ap.IRI(to))},
}
}

View file

@ -5,12 +5,17 @@
package activitypub
import (
"strconv"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/forgefed"
ap "github.com/go-ap/activitypub"
)
func Note(comment *issues_model.Comment) ap.Note {
// Construct a Note object from a comment
func Note(comment *issues_model.Comment) *ap.Note {
note := ap.Note{
Type: ap.NoteType,
AttributedTo: ap.IRI(comment.Poster.GetIRI()),
@ -18,5 +23,50 @@ func Note(comment *issues_model.Comment) ap.Note {
}
note.Content = ap.NaturalLanguageValuesNew()
_ = note.Content.Set("en", ap.Content(comment.Content))
return note
return &note
}
// Construct a Ticket object from an issue
func Ticket(issue *issues_model.Issue) (*forgefed.Ticket, error) {
iri := issue.GetIRI()
ticket := forgefed.TicketNew()
ticket.Type = forgefed.TicketType
ticket.ID = ap.IRI(iri)
// Setting a NaturalLanguageValue to a number causes go-ap's JSON parsing to do weird things
// Workaround: set it to #1 instead of 1
ticket.Name = ap.NaturalLanguageValuesNew()
err := ticket.Name.Set("en", ap.Content("#"+strconv.FormatInt(issue.Index, 10)))
if err != nil {
return nil, err
}
err = issue.LoadRepo(db.DefaultContext)
if err != nil {
return nil, err
}
ticket.Context = ap.IRI(issue.Repo.GetIRI())
err = issue.LoadPoster()
if err != nil {
return nil, err
}
ticket.AttributedTo = ap.IRI(issue.Poster.GetIRI())
ticket.Summary = ap.NaturalLanguageValuesNew()
err = ticket.Summary.Set("en", ap.Content(issue.Title))
if err != nil {
return nil, err
}
ticket.Content = ap.NaturalLanguageValuesNew()
err = ticket.Content.Set("en", ap.Content(issue.Content))
if err != nil {
return nil, err
}
if issue.IsClosed {
ticket.IsResolved = true
}
return ticket, nil
}

View file

@ -14,8 +14,6 @@ import (
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/services/activitypub"
ap "github.com/go-ap/activitypub"
)
// CreateIssueComment creates a plain issue comment.
@ -34,13 +32,8 @@ func CreateIssueComment(doer *user_model.User, repo *repo_model.Repository, issu
if strings.Contains(repo.OwnerName, "@") {
// Federated comment
// Refactor this to its own function in services/activitypub
create := ap.Create{
Type: ap.CreateType,
Object: activitypub.Note(comment),
To: ap.ItemCollection{ap.Item(ap.IRI(repo.OriginalURL + "/inbox"))},
}
err = activitypub.Send(doer, &create)
create := activitypub.Create(repo.OriginalURL + "/inbox", activitypub.Note(comment))
err = activitypub.Send(doer, create)
if err != nil {
return nil, err
}

View file

@ -6,6 +6,7 @@ package issue
import (
"fmt"
"strings"
activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db"
@ -19,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/activitypub"
)
// NewIssue creates new issue with labels for repository.
@ -27,6 +29,19 @@ func NewIssue(repo *repo_model.Repository, issue *issues_model.Issue, labelIDs [
return err
}
if strings.Contains(repo.OwnerName, "@") {
// Federated issue
ticket, err := activitypub.Ticket(issue)
if err != nil {
return err
}
create := activitypub.Create(repo.OriginalURL + "/inbox", ticket)
err = activitypub.Send(issue.Poster, create)
if err != nil {
return err
}
}
for _, assigneeID := range assigneeIDs {
if err := AddAssigneeIfNotAssigned(issue, issue.Poster, assigneeID); err != nil {
return err