Federated issue creation
parent
77896f1a50
commit
3e690fbae2
|
@ -41,6 +41,7 @@ func Repo(ctx *context.APIContext) {
|
||||||
|
|
||||||
iri := ctx.Repo.Repository.GetIRI()
|
iri := ctx.Repo.Repository.GetIRI()
|
||||||
repo := forgefed.RepositoryNew(ap.IRI(iri))
|
repo := forgefed.RepositoryNew(ap.IRI(iri))
|
||||||
|
repo.Type = forgefed.RepositoryType
|
||||||
|
|
||||||
repo.Name = ap.NaturalLanguageValuesNew()
|
repo.Name = ap.NaturalLanguageValuesNew()
|
||||||
err := repo.Name.Set("en", ap.Content(ctx.Repo.Repository.Name))
|
err := repo.Name.Set("en", ap.Content(ctx.Repo.Repository.Name))
|
||||||
|
@ -123,24 +124,27 @@ func RepoInbox(ctx *context.APIContext) {
|
||||||
// Process activity
|
// Process activity
|
||||||
switch activity.Type {
|
switch activity.Type {
|
||||||
case ap.CreateType:
|
case ap.CreateType:
|
||||||
err = ap.OnObject(activity.Object, func(o *ap.Object) error {
|
switch activity.Object.GetType() {
|
||||||
switch o.Type {
|
case forgefed.RepositoryType:
|
||||||
case forgefed.RepositoryType:
|
// Fork created by remote instance
|
||||||
// Fork created by remote instance
|
err = forgefed.OnRepository(activity.Object, func(r *forgefed.Repository) error {
|
||||||
return forgefed.OnRepository(o, func(r *forgefed.Repository) error {
|
return createRepository(ctx, r)
|
||||||
return createRepository(ctx, r)
|
})
|
||||||
})
|
case forgefed.TicketType:
|
||||||
case forgefed.TicketType:
|
// New issue or pull request
|
||||||
// New issue or pull request
|
err = forgefed.OnTicket(activity.Object, func(t *forgefed.Ticket) error {
|
||||||
return forgefed.OnTicket(o, func(t *forgefed.Ticket) error {
|
return createTicket(ctx, t)
|
||||||
return createTicket(ctx, t)
|
})
|
||||||
})
|
case ap.NoteType:
|
||||||
case ap.NoteType:
|
// New comment
|
||||||
// New comment
|
err = ap.On(activity.Object, func(n *ap.Note) error {
|
||||||
return createComment(ctx, o)
|
return createComment(ctx, n)
|
||||||
}
|
})
|
||||||
return nil
|
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:
|
case ap.LikeType:
|
||||||
err = star(ctx, activity)
|
err = star(ctx, activity)
|
||||||
default:
|
default:
|
||||||
|
@ -149,7 +153,7 @@ func RepoInbox(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("Error when processing: %s", err)
|
ctx.ServerError("Error when processing", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
|
|
|
@ -8,12 +8,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
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/context"
|
||||||
"code.gitea.io/gitea/modules/forgefed"
|
"code.gitea.io/gitea/services/activitypub"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ticket function returns the Ticket object for an issue or PR
|
// Ticket function returns the Ticket object for an issue or PR
|
||||||
|
@ -43,63 +39,20 @@ func Ticket(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/ActivityPub"
|
// "$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)
|
index, err := strconv.ParseInt(ctx.Params("id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("ParseInt", err)
|
ctx.ServerError("ParseInt", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
issue, err := issues_model.GetIssueByIndex(repo.ID, index)
|
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetIssueByIndex", err)
|
ctx.ServerError("GetIssueByIndex", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
iri := issue.GetIRI()
|
ticket, err := activitypub.Ticket(issue)
|
||||||
|
|
||||||
// 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")))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("Set Name", err)
|
ctx.ServerError("Ticket", err)
|
||||||
return
|
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)
|
response(ctx, ticket)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))},
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,12 +5,17 @@
|
||||||
package activitypub
|
package activitypub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
"code.gitea.io/gitea/modules/forgefed"
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
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{
|
note := ap.Note{
|
||||||
Type: ap.NoteType,
|
Type: ap.NoteType,
|
||||||
AttributedTo: ap.IRI(comment.Poster.GetIRI()),
|
AttributedTo: ap.IRI(comment.Poster.GetIRI()),
|
||||||
|
@ -18,5 +23,50 @@ func Note(comment *issues_model.Comment) ap.Note {
|
||||||
}
|
}
|
||||||
note.Content = ap.NaturalLanguageValuesNew()
|
note.Content = ap.NaturalLanguageValuesNew()
|
||||||
_ = note.Content.Set("en", ap.Content(comment.Content))
|
_ = note.Content.Set("en", ap.Content(comment.Content))
|
||||||
return note
|
return ¬e
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,6 @@ import (
|
||||||
"code.gitea.io/gitea/modules/notification"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/services/activitypub"
|
"code.gitea.io/gitea/services/activitypub"
|
||||||
|
|
||||||
ap "github.com/go-ap/activitypub"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateIssueComment creates a plain issue comment.
|
// 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, "@") {
|
if strings.Contains(repo.OwnerName, "@") {
|
||||||
// Federated comment
|
// Federated comment
|
||||||
// Refactor this to its own function in services/activitypub
|
create := activitypub.Create(repo.OriginalURL + "/inbox", activitypub.Note(comment))
|
||||||
create := ap.Create{
|
err = activitypub.Send(doer, create)
|
||||||
Type: ap.CreateType,
|
|
||||||
Object: activitypub.Note(comment),
|
|
||||||
To: ap.ItemCollection{ap.Item(ap.IRI(repo.OriginalURL + "/inbox"))},
|
|
||||||
}
|
|
||||||
err = activitypub.Send(doer, &create)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ package issue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
activities_model "code.gitea.io/gitea/models/activities"
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
@ -19,6 +20,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/notification"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
"code.gitea.io/gitea/services/activitypub"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewIssue creates new issue with labels for repository.
|
// 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
|
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 {
|
for _, assigneeID := range assigneeIDs {
|
||||||
if err := AddAssigneeIfNotAssigned(issue, issue.Poster, assigneeID); err != nil {
|
if err := AddAssigneeIfNotAssigned(issue, issue.Poster, assigneeID); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Reference in New Issue