Implement commenting and fix lint errors
parent
3f5f626264
commit
1066cfe785
|
@ -27,6 +27,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/references"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
@ -2471,3 +2472,11 @@ func DeleteOrphanedIssues() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (issue *Issue) GetIRI() string {
|
||||
_ = issue.LoadRepo(db.DefaultContext)
|
||||
if strings.Contains(issue.Repo.OwnerName, "@") {
|
||||
return issue.OriginalAuthor
|
||||
}
|
||||
return setting.AppURL + "api/v1/activitypub/ticket/" + issue.Repo.OwnerName + "/" + issue.Repo.Name + "/" + strconv.FormatInt(issue.Index, 10)
|
||||
}
|
||||
|
|
|
@ -802,3 +802,10 @@ func FixNullArchivedRepository() (int64, error) {
|
|||
IsArchived: false,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Repository) GetIRI() string {
|
||||
if strings.Contains(r.OwnerName, "@") {
|
||||
return r.OriginalURL
|
||||
}
|
||||
return setting.AppURL + "api/v1/activitypub/repo/" + r.OwnerName + "/" + r.Name
|
||||
}
|
||||
|
|
|
@ -1339,3 +1339,10 @@ func GetOrderByName() string {
|
|||
}
|
||||
return "name"
|
||||
}
|
||||
|
||||
func (u *User) GetIRI() string {
|
||||
if u.LoginType == auth.Federated {
|
||||
return u.LoginName
|
||||
}
|
||||
return setting.AppURL + "api/v1/activitypub/user/" + u.Name
|
||||
}
|
||||
|
|
|
@ -62,35 +62,37 @@ func NotEmpty(i ap.Item) bool {
|
|||
if ap.IsNil(i) {
|
||||
return false
|
||||
}
|
||||
var notEmpty bool
|
||||
switch i.GetType() {
|
||||
case CommitType:
|
||||
OnCommit(i, func(c *Commit) error {
|
||||
notEmpty = ap.NotEmpty(c.Object)
|
||||
return nil
|
||||
})
|
||||
case BranchType:
|
||||
OnBranch(i, func(b *Branch) error {
|
||||
notEmpty = ap.NotEmpty(b.Object)
|
||||
return nil
|
||||
})
|
||||
case RepositoryType:
|
||||
OnRepository(i, func(r *Repository) error {
|
||||
notEmpty = ap.NotEmpty(r.Actor)
|
||||
return nil
|
||||
})
|
||||
case PushType:
|
||||
OnPush(i, func(p *Push) error {
|
||||
notEmpty = ap.NotEmpty(p.Object)
|
||||
return nil
|
||||
})
|
||||
case TicketType:
|
||||
OnTicket(i, func(t *Ticket) error {
|
||||
notEmpty = ap.NotEmpty(t.Object)
|
||||
return nil
|
||||
})
|
||||
default:
|
||||
notEmpty = ap.NotEmpty(i)
|
||||
c, err := ToCommit(i)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return notEmpty
|
||||
return ap.NotEmpty(c.Object)
|
||||
case BranchType:
|
||||
b, err := ToBranch(i)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ap.NotEmpty(b.Object)
|
||||
case RepositoryType:
|
||||
r, err := ToRepository(i)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ap.NotEmpty(r.Actor)
|
||||
case PushType:
|
||||
p, err := ToPush(i)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ap.NotEmpty(p.Object)
|
||||
case TicketType:
|
||||
t, err := ToTicket(i)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ap.NotEmpty(t.Object)
|
||||
}
|
||||
return ap.NotEmpty(i)
|
||||
}
|
||||
|
|
|
@ -42,7 +42,12 @@ func AuthorizeInteraction(ctx *context.Context) {
|
|||
switch object.GetType() {
|
||||
case ap.PersonType:
|
||||
// Federated user
|
||||
err = createPerson(ctx, object.(*ap.Person))
|
||||
person, err := ap.ToActor(object)
|
||||
if err != nil {
|
||||
ctx.ServerError("ToActor", err)
|
||||
return
|
||||
}
|
||||
err = createPerson(ctx, person)
|
||||
if err != nil {
|
||||
ctx.ServerError("FederatedUserNew", err)
|
||||
return
|
||||
|
|
|
@ -67,7 +67,10 @@ func createPerson(ctx context.Context, person *ap.Person) error {
|
|||
}
|
||||
|
||||
if person.Icon != nil {
|
||||
icon := person.Icon.(*ap.Image)
|
||||
icon, err := ap.ToObject(person.Icon)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
iconURL, err := icon.URL.GetLink().URL()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -112,7 +115,11 @@ func createPersonFromIRI(ctx context.Context, personIRI ap.IRI) error {
|
|||
}
|
||||
|
||||
// Create federated user
|
||||
return createPerson(ctx, object.(*ap.Person))
|
||||
person, err := ap.ToActor(object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return createPerson(ctx, person)
|
||||
}
|
||||
|
||||
// Create a new federated repo from a Repository object
|
||||
|
@ -134,6 +141,7 @@ func createRepository(ctx context.Context, repository *forgefed.Repository) erro
|
|||
|
||||
repo, err := repo_service.CreateRepository(user, user, repo_module.CreateRepoOptions{
|
||||
Name: repository.Name.String(),
|
||||
OriginalURL: repository.GetLink().String(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -281,7 +289,7 @@ func createComment(ctx context.Context, note *ap.Note) error {
|
|||
return err
|
||||
}
|
||||
|
||||
actorUser, err := activitypub.PersonIRIToUser(ctx, note.AttributedTo.GetLink())
|
||||
user, err := activitypub.PersonIRIToUser(ctx, note.AttributedTo.GetLink())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -299,7 +307,7 @@ func createComment(ctx context.Context, note *ap.Note) error {
|
|||
return err
|
||||
}
|
||||
_, err = issues_model.CreateCommentCtx(ctx, &issues_model.CreateCommentOptions{
|
||||
Doer: actorUser,
|
||||
Doer: user,
|
||||
Repo: repo,
|
||||
Issue: issue,
|
||||
Content: note.Content.String(),
|
||||
|
|
|
@ -42,8 +42,8 @@ func Person(ctx *context.APIContext) {
|
|||
// "200":
|
||||
// "$ref": "#/responses/ActivityPub"
|
||||
|
||||
link := setting.AppURL + "api/v1/activitypub/user/" + ctx.ContextUser.Name
|
||||
person := ap.PersonNew(ap.IRI(link))
|
||||
iri := ctx.ContextUser.GetIRI()
|
||||
person := ap.PersonNew(ap.IRI(iri))
|
||||
|
||||
person.Name = ap.NaturalLanguageValuesNew()
|
||||
err := person.Name.Set("en", ap.Content(ctx.ContextUser.FullName))
|
||||
|
@ -68,14 +68,14 @@ func Person(ctx *context.APIContext) {
|
|||
URL: ap.IRI(ctx.ContextUser.AvatarFullLinkWithSize(2048)),
|
||||
}
|
||||
|
||||
person.Inbox = ap.IRI(link + "/inbox")
|
||||
person.Outbox = ap.IRI(link + "/outbox")
|
||||
person.Following = ap.IRI(link + "/following")
|
||||
person.Followers = ap.IRI(link + "/followers")
|
||||
person.Liked = ap.IRI(link + "/liked")
|
||||
person.Inbox = ap.IRI(iri + "/inbox")
|
||||
person.Outbox = ap.IRI(iri + "/outbox")
|
||||
person.Following = ap.IRI(iri + "/following")
|
||||
person.Followers = ap.IRI(iri + "/followers")
|
||||
person.Liked = ap.IRI(iri + "/liked")
|
||||
|
||||
person.PublicKey.ID = ap.IRI(link + "#main-key")
|
||||
person.PublicKey.Owner = ap.IRI(link)
|
||||
person.PublicKey.ID = ap.IRI(iri + "#main-key")
|
||||
person.PublicKey.Owner = ap.IRI(iri)
|
||||
publicKeyPem, err := activitypub.GetPublicKey(ctx.ContextUser)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetPublicKey", err)
|
||||
|
@ -164,13 +164,13 @@ func PersonOutbox(ctx *context.APIContext) {
|
|||
// "200":
|
||||
// "$ref": "#/responses/ActivityPub"
|
||||
|
||||
link := setting.AppURL + "api/v1/activitypub/user/" + ctx.ContextUser.Name
|
||||
iri := ctx.ContextUser.GetIRI()
|
||||
|
||||
orderedCollection := ap.OrderedCollectionNew(ap.IRI(link + "/outbox"))
|
||||
orderedCollection.First = ap.IRI(link + "/outbox?page=1")
|
||||
orderedCollection := ap.OrderedCollectionNew(ap.IRI(iri + "/outbox"))
|
||||
orderedCollection.First = ap.IRI(iri + "/outbox?page=1")
|
||||
|
||||
outbox := ap.OrderedCollectionPageNew(orderedCollection)
|
||||
outbox.First = ap.IRI(link + "/outbox?page=1")
|
||||
outbox.First = ap.IRI(iri + "/outbox?page=1")
|
||||
|
||||
feed, err := activities.GetFeeds(ctx, activities.GetFeedsOptions{
|
||||
RequestedUser: ctx.ContextUser,
|
||||
|
@ -183,12 +183,12 @@ func PersonOutbox(ctx *context.APIContext) {
|
|||
|
||||
// Only specify next if this amount of feed corresponds to the calculated limit.
|
||||
if len(feed) == convert.ToCorrectPageSize(ctx.FormInt("limit")) {
|
||||
outbox.Next = ap.IRI(fmt.Sprintf("%s/outbox?page=%d", link, ctx.FormInt("page")+1))
|
||||
outbox.Next = ap.IRI(fmt.Sprintf("%s/outbox?page=%d", iri, ctx.FormInt("page")+1))
|
||||
}
|
||||
|
||||
// Only specify previous page when there is one.
|
||||
if ctx.FormInt("page") > 1 {
|
||||
outbox.Prev = ap.IRI(fmt.Sprintf("%s/outbox?page=%d", link, ctx.FormInt("page")-1))
|
||||
outbox.Prev = ap.IRI(fmt.Sprintf("%s/outbox?page=%d", iri, ctx.FormInt("page")-1))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -249,7 +249,7 @@ func PersonFollowing(ctx *context.APIContext) {
|
|||
// "200":
|
||||
// "$ref": "#/responses/ActivityPub"
|
||||
|
||||
link := setting.AppURL + "api/v1/activitypub/user/" + ctx.ContextUser.Name
|
||||
iri := ctx.ContextUser.GetIRI()
|
||||
|
||||
users, _, err := user_model.GetUserFollowing(ctx, ctx.ContextUser, ctx.Doer, utils.GetListOptions(ctx))
|
||||
if err != nil {
|
||||
|
@ -257,7 +257,7 @@ func PersonFollowing(ctx *context.APIContext) {
|
|||
return
|
||||
}
|
||||
|
||||
following := ap.OrderedCollectionNew(ap.IRI(link + "/following"))
|
||||
following := ap.OrderedCollectionNew(ap.IRI(iri + "/following"))
|
||||
following.TotalItems = uint(len(users))
|
||||
|
||||
for _, user := range users {
|
||||
|
@ -290,7 +290,7 @@ func PersonFollowers(ctx *context.APIContext) {
|
|||
// "200":
|
||||
// "$ref": "#/responses/ActivityPub"
|
||||
|
||||
link := setting.AppURL + "api/v1/activitypub/user/" + ctx.ContextUser.Name
|
||||
iri := ctx.ContextUser.GetIRI()
|
||||
|
||||
users, _, err := user_model.GetUserFollowers(ctx, ctx.ContextUser, ctx.Doer, utils.GetListOptions(ctx))
|
||||
if err != nil {
|
||||
|
@ -298,7 +298,7 @@ func PersonFollowers(ctx *context.APIContext) {
|
|||
return
|
||||
}
|
||||
|
||||
followers := ap.OrderedCollectionNew(ap.IRI(link + "/followers"))
|
||||
followers := ap.OrderedCollectionNew(ap.IRI(iri + "/followers"))
|
||||
followers.TotalItems = uint(len(users))
|
||||
|
||||
for _, user := range users {
|
||||
|
@ -331,7 +331,7 @@ func PersonLiked(ctx *context.APIContext) {
|
|||
// "200":
|
||||
// "$ref": "#/responses/ActivityPub"
|
||||
|
||||
link := setting.AppURL + "api/v1/activitypub/user/" + ctx.ContextUser.Name
|
||||
iri := ctx.ContextUser.GetIRI()
|
||||
|
||||
repos, count, err := repo_model.SearchRepository(&repo_model.SearchRepoOptions{
|
||||
Actor: ctx.Doer,
|
||||
|
@ -343,7 +343,7 @@ func PersonLiked(ctx *context.APIContext) {
|
|||
return
|
||||
}
|
||||
|
||||
liked := ap.OrderedCollectionNew(ap.IRI(link + "/liked"))
|
||||
liked := ap.OrderedCollectionNew(ap.IRI(iri + "/liked"))
|
||||
liked.TotalItems = uint(count)
|
||||
|
||||
for _, repo := range repos {
|
||||
|
|
|
@ -39,8 +39,8 @@ func Repo(ctx *context.APIContext) {
|
|||
// "200":
|
||||
// "$ref": "#/responses/ActivityPub"
|
||||
|
||||
link := setting.AppURL + "api/v1/activitypub/repo/" + ctx.ContextUser.Name + "/" + ctx.Repo.Repository.Name
|
||||
repo := forgefed.RepositoryNew(ap.IRI(link))
|
||||
iri := ctx.Repo.Repository.GetIRI()
|
||||
repo := forgefed.RepositoryNew(ap.IRI(iri))
|
||||
|
||||
repo.Name = ap.NaturalLanguageValuesNew()
|
||||
err := repo.Name.Set("en", ap.Content(ctx.Repo.Repository.Name))
|
||||
|
@ -58,10 +58,10 @@ func Repo(ctx *context.APIContext) {
|
|||
return
|
||||
}
|
||||
|
||||
repo.Inbox = ap.IRI(link + "/inbox")
|
||||
repo.Outbox = ap.IRI(link + "/outbox")
|
||||
repo.Followers = ap.IRI(link + "/followers")
|
||||
repo.Team = ap.IRI(link + "/team")
|
||||
repo.Inbox = ap.IRI(iri + "/inbox")
|
||||
repo.Outbox = ap.IRI(iri + "/outbox")
|
||||
repo.Followers = ap.IRI(iri + "/followers")
|
||||
repo.Team = ap.IRI(iri + "/team")
|
||||
|
||||
response(ctx, repo)
|
||||
}
|
||||
|
|
|
@ -43,12 +43,6 @@ func Ticket(ctx *context.APIContext) {
|
|||
// "200":
|
||||
// "$ref": "#/responses/ActivityPub"
|
||||
|
||||
link := setting.AppURL + "api/v1/activitypub/ticket/" + ctx.ContextUser.Name + "/" + ctx.Repo.Repository.Name + "/" + ctx.Params("id")
|
||||
|
||||
ticket := forgefed.TicketNew()
|
||||
ticket.Type = forgefed.TicketType
|
||||
ticket.ID = ap.IRI(link)
|
||||
|
||||
repo, err := repo_model.GetRepositoryByOwnerAndNameCtx(ctx, ctx.ContextUser.Name, ctx.Repo.Repository.Name)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetRepositoryByOwnerAndNameCtx", err)
|
||||
|
@ -64,6 +58,12 @@ func Ticket(ctx *context.APIContext) {
|
|||
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
|
||||
|
|
|
@ -12,42 +12,22 @@ import (
|
|||
)
|
||||
|
||||
// Create and send Follow activity
|
||||
func Follow(userID, followID int64) error {
|
||||
followUser, err := user_model.GetUserByID(followID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
actorUser, err := user_model.GetUserByID(userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func Follow(actorUser, followUser *user_model.User) *ap.Follow {
|
||||
object := ap.PersonNew(ap.IRI(followUser.LoginName))
|
||||
follow := ap.FollowNew("", object)
|
||||
follow.Type = ap.FollowType
|
||||
follow.Actor = ap.PersonNew(ap.IRI(setting.AppURL + "api/v1/activitypub/user/" + actorUser.Name))
|
||||
follow.To = ap.ItemCollection{ap.Item(ap.IRI(followUser.LoginName + "/inbox"))}
|
||||
return Send(actorUser, follow)
|
||||
return follow
|
||||
}
|
||||
|
||||
// Create and send Undo Follow activity
|
||||
func Unfollow(userID, followID int64) error {
|
||||
followUser, err := user_model.GetUserByID(followID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
actorUser, err := user_model.GetUserByID(userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func Unfollow(actorUser, followUser *user_model.User) *ap.Undo {
|
||||
object := ap.PersonNew(ap.IRI(followUser.LoginName))
|
||||
follow := ap.FollowNew("", object)
|
||||
follow.Actor = ap.PersonNew(ap.IRI(setting.AppURL + "api/v1/activitypub/user/" + actorUser.Name))
|
||||
unfollow := ap.UndoNew("", follow)
|
||||
unfollow.Type = ap.UndoType
|
||||
unfollow.To = ap.ItemCollection{ap.Item(ap.IRI(followUser.LoginName + "/inbox"))}
|
||||
return Send(actorUser, unfollow)
|
||||
return unfollow
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// 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 (
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
|
||||
ap "github.com/go-ap/activitypub"
|
||||
)
|
||||
|
||||
func Note(comment *issues_model.Comment) ap.Note {
|
||||
note := ap.Note{
|
||||
Type: ap.NoteType,
|
||||
AttributedTo: ap.IRI(comment.Poster.GetIRI()),
|
||||
Context: ap.IRI(comment.Issue.GetIRI()),
|
||||
}
|
||||
note.Content = ap.NaturalLanguageValuesNew()
|
||||
_ = note.Content.Set("en", ap.Content(comment.Content))
|
||||
return note
|
||||
}
|
|
@ -5,12 +5,17 @@
|
|||
package comments
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"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.
|
||||
|
@ -27,6 +32,20 @@ func CreateIssueComment(doer *user_model.User, repo *repo_model.Repository, issu
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if strings.Contains(repo.Owner.Name, "@") {
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
mentions, err := issues_model.FindAndUpdateIssueMentions(db.DefaultContext, issue, doer, comment.Content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -295,9 +295,13 @@ func FollowUser(userID, followID int64) (err error) {
|
|||
}
|
||||
if followUser.LoginType == auth.Federated {
|
||||
// Following remote user
|
||||
err = activitypub.Follow(userID, followID)
|
||||
actorUser, err := user_model.GetUserByID(userID)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
err = activitypub.Send(actorUser, activitypub.Follow(actorUser, followUser))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,9 +320,13 @@ func UnfollowUser(userID, followID int64) (err error) {
|
|||
}
|
||||
if followUser.LoginType == auth.Federated {
|
||||
// Unfollowing remote user
|
||||
err = activitypub.Unfollow(userID, followID)
|
||||
actorUser, err := user_model.GetUserByID(userID)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
err = activitypub.Send(actorUser, activitypub.Unfollow(actorUser, followUser))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue