Federated issue creation
parent
77896f1a50
commit
3e690fbae2
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
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 ¬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/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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue