diff --git a/routers/api/v1/activitypub/create.go b/routers/api/v1/activitypub/create.go index 043b97ae65..b8f005970b 100644 --- a/routers/api/v1/activitypub/create.go +++ b/routers/api/v1/activitypub/create.go @@ -212,7 +212,7 @@ func createIssue(ctx context.Context, ticket *forgefed.Ticket) error { OriginalAuthor: ticket.GetLink().String(), // Create new database field to store IRI? IsClosed: ticket.IsResolved, } - return issue_service.NewIssue(repo, issue, nil, nil, nil) + return issue_service.NewIssue(ctx, repo, issue, nil, nil, nil) } // Create a pull request diff --git a/routers/api/v1/activitypub/follow.go b/routers/api/v1/activitypub/follow.go index 2badcaf8f0..54e611f89d 100644 --- a/routers/api/v1/activitypub/follow.go +++ b/routers/api/v1/activitypub/follow.go @@ -39,9 +39,9 @@ func follow(ctx context.Context, follow ap.Follow) error { // Send back an Accept activity accept := ap.AcceptNew(objectIRI, follow) accept.Actor = ap.Person{ID: objectIRI} - accept.To = ap.ItemCollection{ap.IRI(actorIRI.String() + "/inbox")} + accept.To = ap.ItemCollection{ap.IRI(actorIRI.String())} accept.Object = follow - return activitypub.Send(objectUser, accept) + return activitypub.Send(ctx, objectUser, accept) } // Process an incoming Undo follow activity diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index fecb601dd5..529211253e 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -644,7 +644,7 @@ func CreateIssue(ctx *context.APIContext) { form.Labels = make([]int64, 0) } - if err := issue_service.NewIssue(ctx.Repo.Repository, issue, form.Labels, nil, assigneeIDs); err != nil { + if err := issue_service.NewIssue(ctx, ctx.Repo.Repository, issue, form.Labels, nil, assigneeIDs); err != nil { if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) { ctx.Error(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err) return diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index b081092c57..f3b72da3b8 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1085,7 +1085,7 @@ func NewIssuePost(ctx *context.Context) { Ref: form.Ref, } - if err := issue_service.NewIssue(repo, issue, labelIDs, attachments, assigneeIDs); err != nil { + if err := issue_service.NewIssue(ctx, repo, issue, labelIDs, attachments, assigneeIDs); err != nil { if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) { ctx.Error(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err.Error()) return diff --git a/services/activitypub/activities.go b/services/activitypub/activities.go index c684a19783..617c38ae41 100644 --- a/services/activitypub/activities.go +++ b/services/activitypub/activities.go @@ -17,7 +17,7 @@ func Follow(actorUser, followUser *user_model.User) *ap.Follow { Type: ap.FollowType, Actor: ap.PersonNew(ap.IRI(actorUser.GetIRI())), Object: ap.PersonNew(ap.IRI(followUser.GetIRI())), - To: ap.ItemCollection{ap.IRI(followUser.GetIRI() + "/inbox")}, + To: ap.ItemCollection{ap.IRI(followUser.GetIRI())}, } } @@ -27,7 +27,7 @@ func Unfollow(actorUser, followUser *user_model.User) *ap.Undo { Type: ap.UndoType, Actor: ap.PersonNew(ap.IRI(actorUser.GetIRI())), Object: Follow(actorUser, followUser), - To: ap.ItemCollection{ap.IRI(followUser.GetIRI() + "/inbox")}, + To: ap.ItemCollection{ap.IRI(followUser.GetIRI())}, } } @@ -37,7 +37,7 @@ func Star(user *user_model.User, repo *repo_model.Repository) *ap.Like { Type: ap.LikeType, Actor: ap.PersonNew(ap.IRI(user.GetIRI())), Object: forgefed.RepositoryNew(ap.IRI(repo.GetIRI())), - To: ap.ItemCollection{ap.IRI(repo.GetIRI() + "/inbox")}, + To: ap.ItemCollection{ap.IRI(repo.GetIRI())}, } } @@ -47,7 +47,7 @@ func Unstar(user *user_model.User, repo *repo_model.Repository) *ap.Undo { Type: ap.UndoType, Actor: ap.PersonNew(ap.IRI(user.GetIRI())), Object: Star(user, repo), - To: ap.ItemCollection{ap.IRI(repo.GetIRI() + "/inbox")}, + To: ap.ItemCollection{ap.IRI(repo.GetIRI())}, } } @@ -57,6 +57,6 @@ func Create(user *user_model.User, object ap.ObjectOrLink, to string) *ap.Create Type: ap.CreateType, Actor: ap.PersonNew(ap.IRI(user.GetIRI())), Object: object, - To: ap.ItemCollection{ap.IRI(to + "/inbox")}, + To: ap.ItemCollection{ap.IRI(to)}, } } diff --git a/services/activitypub/transport.go b/services/activitypub/transport.go index 3d13aec75d..a7621e2f10 100644 --- a/services/activitypub/transport.go +++ b/services/activitypub/transport.go @@ -4,10 +4,13 @@ package activitypub import ( + "context" "fmt" "io" "net/http" + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/forgefed" "code.gitea.io/gitea/modules/httplib" @@ -50,7 +53,7 @@ func FetchObject(iri string) (ap.ObjectOrLink, error) { } // Send an activity -func Send(user *user_model.User, activity *ap.Activity) error { +func Send(ctx context.Context, user *user_model.User, activity *ap.Activity) error { binary, err := jsonld.WithContext( jsonld.IRI(ap.ActivityBaseURI), jsonld.IRI(ap.SecurityContextURI), @@ -60,11 +63,39 @@ func Send(user *user_model.User, activity *ap.Activity) error { return err } + // Construt list of recipients + recipients := []string{} for _, to := range activity.To { - client, _ := NewClient(user, user.GetIRI()+"#main-key") - resp, _ := client.Post(binary, to.GetLink().String()) - respBody, _ := io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize)) + if to.GetLink().String() == user.GetIRI()+"/followers" { + followers, count, err := user_model.GetUserFollowers(ctx, user, user, db.ListOptions{}) + if err != nil { + return err + } + for i := int64(0); i < count; i++ { + if followers[i].LoginType == auth.Federated { + recipients = append(recipients, followers[i].GetIRI()) + } + } + } else { + recipients = append(recipients, to.GetLink().String()) + } + } + + // Send out activity to recipients + for _, recipient := range recipients { + client, err := NewClient(user, user.GetIRI()+"#main-key") + if err != nil { + return err + } + resp, err := client.Post(binary, recipient) + if err != nil { + return err + } + respBody, err := io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize)) + if err != nil { + return err + } log.Trace("Response from sending activity", string(respBody)) } - return err + return nil } diff --git a/services/issue/comments.go b/services/issue/comments.go index 19abbdda7c..0aadf99444 100644 --- a/services/issue/comments.go +++ b/services/issue/comments.go @@ -87,7 +87,7 @@ func CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_m return nil, err } create := activitypub.Create(doer, note, repo.GetIRI()) - err = activitypub.Send(doer, create) + err = activitypub.Send(ctx, doer, create) if err != nil { return nil, err } diff --git a/services/issue/issue.go b/services/issue/issue.go index 31fc7631d2..f9ca4b9ed1 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -4,6 +4,7 @@ package issue import ( + "context" "fmt" "strings" @@ -22,7 +23,7 @@ import ( ) // NewIssue creates new issue with labels for repository. -func NewIssue(repo *repo_model.Repository, issue *issues_model.Issue, labelIDs []int64, uuids []string, assigneeIDs []int64) error { +func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *issues_model.Issue, labelIDs []int64, uuids []string, assigneeIDs []int64) error { if err := issues_model.NewIssue(repo, issue, labelIDs, uuids); err != nil { return err } @@ -38,7 +39,7 @@ func NewIssue(repo *repo_model.Repository, issue *issues_model.Issue, labelIDs [ return err } create := activitypub.Create(issue.Poster, ticket, repo.GetIRI()) - err = activitypub.Send(issue.Poster, create) + err = activitypub.Send(ctx, issue.Poster, create) if err != nil { return err } diff --git a/services/repository/activitypub.go b/services/repository/activitypub.go index e7aa2357bb..65d8efc8cd 100644 --- a/services/repository/activitypub.go +++ b/services/repository/activitypub.go @@ -35,11 +35,11 @@ func CreateFork(ctx context.Context, instance, username, reponame, destUsername // Send a Create activity to the instance we are forking from create := ap.Create{Type: ap.CreateType} - create.To = ap.ItemCollection{ap.IRI("https://" + instance + "/api/v1/activitypub/repo/" + username + "/" + reponame + "/inbox")} + create.To = ap.ItemCollection{ap.IRI("https://" + instance + "/api/v1/activitypub/repo/" + username + "/" + reponame)} repo := ap.IRI(setting.AppURL + "api/v1/activitypub/repo/" + destUsername + "/" + reponame) // repo := forgefed.RepositoryNew(ap.IRI(setting.AppURL + "api/v1/activitypub/repo/" + destUsername + "/" + reponame)) // repo.ForkedFrom = forgefed.RepositoryNew(ap.IRI()) create.Object = repo - return activitypub.Send(user, &create) + return activitypub.Send(ctx, user, &create) } diff --git a/services/repository/star.go b/services/repository/star.go index be78ae4de1..d6e740c946 100644 --- a/services/repository/star.go +++ b/services/repository/star.go @@ -7,7 +7,6 @@ import ( "context" "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/services/activitypub" @@ -37,7 +36,7 @@ func StarRepo(ctx context.Context, userID, repoID int64, star bool) error { } else { activity = activitypub.Unstar(user, repo) } - err = activitypub.Send(user, activity) + err = activitypub.Send(ctx, user, activity) if err != nil { return err } @@ -50,10 +49,7 @@ func StarRepo(ctx context.Context, userID, repoID int64, star bool) error { if err != nil { return err } - followers, count, err := user_model.GetUserFollowers(ctx, user, user, db.ListOptions{}) - if err != nil { - return err - } + note := ap.Note{ Type: ap.NoteType, ID: ap.IRI(repo.GetIRI()), // TODO: serve the note at an API endpoint @@ -69,12 +65,7 @@ func StarRepo(ctx context.Context, userID, repoID int64, star bool) error { Type: ap.CreateType, Actor: ap.PersonNew(ap.IRI(user.GetIRI())), Object: note, - To: ap.ItemCollection{}, + To: ap.ItemCollection{ap.IRI(user.GetIRI() + "/followers")}, } - for i := int64(0); i < count; i++ { - if followers[i].LoginType == auth.Federated { - create.To.Append(ap.IRI(followers[i].GetIRI() + "/inbox")) - } - } - return activitypub.Send(user, &create) + return activitypub.Send(ctx, user, &create) } diff --git a/services/user/user.go b/services/user/user.go index 850198b6ca..817e825ca5 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -293,7 +293,7 @@ func FollowUser(ctx context.Context, userID, followID int64) (err error) { if err != nil { return err } - err = activitypub.Send(actorUser, activitypub.Follow(actorUser, followUser)) + err = activitypub.Send(ctx, actorUser, activitypub.Follow(actorUser, followUser)) if err != nil { return err } @@ -318,7 +318,7 @@ func UnfollowUser(ctx context.Context, userID, followID int64) (err error) { if err != nil { return err } - err = activitypub.Send(actorUser, activitypub.Unfollow(actorUser, followUser)) + err = activitypub.Send(ctx, actorUser, activitypub.Unfollow(actorUser, followUser)) if err != nil { return err }